mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-23 00:59:17 +01:00
Improve NCE and Finish Up Refactor
This commit mainly finishes up refactor by fixing everything brought up in the CR + Improving NCE somewhat and actually killing the child processes properly now.
This commit is contained in:
parent
c76ef3730b
commit
05f3e3c3ac
@ -2,16 +2,21 @@
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="RIGHT_MARGIN" value="400" />
|
||||
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
|
||||
<option name="FORMATTER_TAGS_ENABLED" value="true" />
|
||||
<option name="SOFT_MARGINS" value="80,140" />
|
||||
<JetCodeStyleSettings>
|
||||
<option name="SPACE_BEFORE_TYPE_COLON" value="true" />
|
||||
</JetCodeStyleSettings>
|
||||
<Objective-C>
|
||||
<option name="INDENT_VISIBILITY_KEYWORDS" value="2" />
|
||||
<option name="INDENT_PREPROCESSOR_DIRECTIVE" value="4" />
|
||||
<option name="INDENT_DIRECTIVE_AS_CODE" value="true" />
|
||||
<option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_NESTED_NAMESPACES_IN_ONE_LINE" value="true" />
|
||||
<option name="FUNCTION_NON_TOP_AFTER_RETURN_TYPE_WRAP" value="0" />
|
||||
<option name="FUNCTION_TOP_AFTER_RETURN_TYPE_WRAP" value="0" />
|
||||
<option name="FUNCTION_PARAMETERS_WRAP" value="0" />
|
||||
<option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="5" />
|
||||
<option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="0" />
|
||||
<option name="SHIFT_OPERATION_WRAP" value="0" />
|
||||
<option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" />
|
||||
<option name="CLASS_CONSTRUCTOR_INIT_LIST_WRAP" value="0" />
|
||||
@ -82,6 +87,7 @@
|
||||
<option name="WRAP_LONG_LINES" value="true" />
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="ObjectiveC">
|
||||
<option name="RIGHT_MARGIN" value="999" />
|
||||
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
|
||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
@ -92,7 +98,6 @@
|
||||
<option name="TERNARY_OPERATION_WRAP" value="0" />
|
||||
<option name="FOR_STATEMENT_WRAP" value="1" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
|
||||
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
|
||||
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||
<option name="SOFT_MARGINS" value="140" />
|
||||
<indentOptions>
|
||||
@ -209,5 +214,8 @@
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="RIGHT_MARGIN" value="999" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
@ -1,6 +1,6 @@
|
||||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="SPDX-License-Identifier: MPL-2.0 Copyright © &#36;today.year Skyline Team and Contributors (https://github.com/skyline-emu/)" />
|
||||
<option name="myName" value="Skyline-LGPLv3-or-later" />
|
||||
<option name="myName" value="Skyline-License" />
|
||||
</copyright>
|
||||
</component>
|
@ -1,7 +1,7 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings>
|
||||
<module2copyright>
|
||||
<element module="SkylineKotlin" copyright="Skyline-LGPLv3-or-later" />
|
||||
<element module="SkylineKotlin" copyright="Skyline-License" />
|
||||
</module2copyright>
|
||||
</settings>
|
||||
</component>
|
@ -46,7 +46,8 @@ Use doxygen style comments for:
|
||||
* Enumerations - Use a `/**` block comment with a brief for the enum itself and a `//!<` single-line comment for all the individual items
|
||||
|
||||
Notes:
|
||||
* The DeviceState object can be skipped from function argument documentation as well as class members in the constructor
|
||||
* The `DeviceState` object or other objects which are systematically used throughout multiple classes such as `ServiceManager` can be skipped from function argument documentation as well as class members in the constructor
|
||||
* The `KSession`, `IpcRequest` and `IpcResponse` objects in IPC command function arguments and other such objects (Such as `IoctlData`) can be skipped from function argument documentation if used in those contexts, they will need to be documented if they're used as a class member or something on those lines
|
||||
* Any class members don't need to be redundantly documented in the constructor
|
||||
|
||||
### Spacing
|
||||
@ -190,17 +191,23 @@ void ClassConstructor(const Class& class) : class(class) {} // Make a copy direc
|
||||
Use C++ range-based iterators for any C++ container iteration unless it can be performed better with functional programming (After C++20 when they are merged with the container). In addition, stick to using references/const references using them
|
||||
|
||||
### Usage of auto
|
||||
Use `auto` unless a variable needs to be a specific type that isn't automatically deducible.
|
||||
Use `auto` to assign a variable the type of the value it's being assigned to, but not where a different type is desired. So, as a rule of thumb always specify the type when setting something from a number rather than depending on `auto`. In addition, prefer not to use `auto` in cases where it's hard to determine the return type due to assigned value being complex.
|
||||
```cpp
|
||||
u16 a = 20; // Only if `a` is required to specifically be 16-bit, otherwise integers should be auto
|
||||
Handle b = 0x10; // Handle is a specific type that won't be automatically assigned
|
||||
u8 a = 20; // `20` won't be stored in a `u8` but rather in a `int` (i32, generally) if `auto` is used
|
||||
auto b = std::make_shared<Something>(); // In this case `auto` is used to avoid typing out `std::shared_ptr<Something>`
|
||||
```
|
||||
|
||||
### Primitive Types
|
||||
We generally use `in` and `un` where `n = {8, 16, 32, 64}` for our integer primitives in which `i` represents signed integers and `u` represents unsigned integers. In addition, we have some other types such as `KHandle` that are used to make certain operations more clear, use these depending on the context.
|
||||
|
||||
### Constants
|
||||
If a variable is constant at compile time use `constexpr`, if it's only used in a local function then place it in the function but if it's used throughout a class then in the corresponding header add the variable to the `skyline::constant` namespace. If a constant is used throughout the codebase, add it to `common.h`.
|
||||
|
||||
In addition, try to `constexpr` as much as possible including constructors and functions so that they may be initialized at compile-time and have lesser runtime overhead during usage and certain values can be pre-calculated in advance.
|
||||
|
||||
We should also mention that this isn't promoting the usage of `const`, it's use is actually discouraged out of references, in which case it is extremely encouraged. In addition, pointers are a general exception to this, using `const` with them isn't encouraged nor discouraged. Another exception are class functions, they can be made `const` if used from a `const` reference/pointer and don't
|
||||
modify any members but do not do this preemptively.
|
||||
|
||||
## Kotlin
|
||||
### Naming rules
|
||||
* Enumerator: `PascalCase` **(1)**
|
||||
|
@ -34,7 +34,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
||||
std::signal(SIGABRT, signalHandler);
|
||||
std::signal(SIGFPE, signalHandler);
|
||||
|
||||
setpriority(PRIO_PROCESS, static_cast<id_t>(getpid()), skyline::constant::AndroidPriority.second);
|
||||
setpriority(PRIO_PROCESS, static_cast<id_t>(gettid()), -8); // Set the priority of this process to the highest value
|
||||
|
||||
auto jvmManager = std::make_shared<skyline::JvmManager>(env, instance);
|
||||
auto settings = std::make_shared<skyline::Settings>(preferenceFd);
|
||||
@ -45,7 +45,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
||||
|
||||
try {
|
||||
skyline::kernel::OS os(jvmManager, logger, settings);
|
||||
const char *romUri = env->GetStringUTFChars(romUriJstring, nullptr);
|
||||
auto romUri = env->GetStringUTFChars(romUriJstring, nullptr);
|
||||
logger->Info("Launching ROM {}", romUri);
|
||||
env->ReleaseStringUTFChars(romUriJstring, romUri);
|
||||
os.Execute(romFd, static_cast<skyline::TitleFormat>(romType));
|
||||
|
@ -16,7 +16,7 @@ namespace skyline::audio {
|
||||
outputStream->requestStart();
|
||||
}
|
||||
|
||||
std::shared_ptr<AudioTrack> Audio::OpenTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback) {
|
||||
std::shared_ptr<AudioTrack> Audio::OpenTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback) {
|
||||
std::lock_guard trackGuard(trackLock);
|
||||
|
||||
auto track = std::make_shared<AudioTrack>(channelCount, sampleRate, releaseCallback);
|
||||
@ -33,8 +33,8 @@ namespace skyline::audio {
|
||||
}
|
||||
|
||||
oboe::DataCallbackResult Audio::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
|
||||
i16 *destBuffer = static_cast<i16 *>(audioData);
|
||||
size_t streamSamples = static_cast<size_t>(numFrames) * audioStream->getChannelCount();
|
||||
auto destBuffer = static_cast<i16 *>(audioData);
|
||||
auto streamSamples = static_cast<size_t>(numFrames) * audioStream->getChannelCount();
|
||||
size_t writtenSamples = 0;
|
||||
|
||||
std::unique_lock trackGuard(trackLock);
|
||||
|
@ -32,7 +32,7 @@ namespace skyline::audio {
|
||||
* @param releaseCallback The callback to call when a buffer has been released
|
||||
* @return A shared pointer to a new AudioTrack object
|
||||
*/
|
||||
std::shared_ptr<AudioTrack> OpenTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback);
|
||||
std::shared_ptr<AudioTrack> OpenTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback);
|
||||
|
||||
/**
|
||||
* @brief Closes a track and frees its data
|
||||
|
@ -8,10 +8,10 @@
|
||||
|
||||
namespace skyline {
|
||||
namespace constant {
|
||||
constexpr auto SampleRate = 48000; //!< The common sampling rate to use for audio output
|
||||
constexpr auto ChannelCount = 2; //!< The common amount of channels to use for audio output
|
||||
constexpr u16 SampleRate = 48000; //!< The common sampling rate to use for audio output
|
||||
constexpr u8 ChannelCount = 2; //!< The common amount of channels to use for audio output
|
||||
constexpr u16 MixBufferSize = 960; //!< The size of the mix buffer by default
|
||||
constexpr auto PcmFormat = oboe::AudioFormat::I16; //!< The common PCM data format to use for audio output
|
||||
constexpr size_t MixBufferSize = 960; //!< The size of the mix buffer by default
|
||||
};
|
||||
|
||||
namespace audio {
|
||||
|
@ -6,13 +6,17 @@
|
||||
#include "resampler.h"
|
||||
|
||||
namespace skyline::audio {
|
||||
/**
|
||||
* @brief This holds the coefficients of a single output frame
|
||||
*/
|
||||
struct LutEntry {
|
||||
i32 a;
|
||||
i32 b;
|
||||
i32 c;
|
||||
i32 d;
|
||||
i32 a; //!< The coefficient for the first index
|
||||
i32 b; //!< The coefficient for the second index
|
||||
i32 c; //!< The coefficient for the third index
|
||||
i32 d; //!< The coefficient for the fourth index
|
||||
};
|
||||
|
||||
// @formatter:off
|
||||
constexpr std::array<LutEntry, 128> CurveLut0 = {{
|
||||
{6600, 19426, 6722, 3}, {6479, 19424, 6845, 9}, {6359, 19419, 6968, 15}, {6239, 19412, 7093, 22},
|
||||
{6121, 19403, 7219, 28}, {6004, 19391, 7345, 34}, {5888, 19377, 7472, 41}, {5773, 19361, 7600, 48},
|
||||
@ -114,9 +118,10 @@ namespace skyline::audio {
|
||||
{-76, 5004, 25919, 1912}, {-72, 4837, 25980, 2015}, {-67, 4673, 26035, 2120}, {-63, 4512, 26085, 2227},
|
||||
{-58, 4354, 26130, 2338}, {-54, 4199, 26169, 2451}, {-50, 4046, 26202, 2568}, {-46, 3897, 26230, 2688},
|
||||
{-42, 3751, 26253, 2811}, {-38, 3608, 26270, 2936}, {-34, 3467, 26281, 3064}, {-32, 3329, 26287, 3195}}};
|
||||
// @formatter:on
|
||||
|
||||
std::vector<i16> Resampler::ResampleBuffer(const std::vector<i16> &inputBuffer, double ratio, u8 channelCount) {
|
||||
auto step = static_cast<uint>(ratio * 0x8000);
|
||||
auto step = static_cast<u32>(ratio * 0x8000);
|
||||
auto outputSize = static_cast<size_t>(inputBuffer.size() / ratio);
|
||||
std::vector<i16> outputBuffer(outputSize);
|
||||
|
||||
@ -129,7 +134,7 @@ namespace skyline::audio {
|
||||
return CurveLut2;
|
||||
}();
|
||||
|
||||
for (auto outIndex = 0, inIndex = 0; outIndex < outputBuffer.size(); outIndex += channelCount) {
|
||||
for (size_t outIndex = 0, inIndex = 0; outIndex < outputSize; outIndex += channelCount) {
|
||||
auto lutIndex = (fraction >> 8) << 2;
|
||||
|
||||
for (u8 channel = 0; channel < channelCount; channel++) {
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "track.h"
|
||||
|
||||
namespace skyline::audio {
|
||||
AudioTrack::AudioTrack(const u8 channelCount, const u32 sampleRate, const std::function<void()> &releaseCallback) : channelCount(channelCount), sampleRate(sampleRate), releaseCallback(releaseCallback) {
|
||||
AudioTrack::AudioTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback) : channelCount(channelCount), sampleRate(sampleRate), releaseCallback(releaseCallback) {
|
||||
if (sampleRate != constant::SampleRate)
|
||||
throw exception("Unsupported audio sample rate: {}", sampleRate);
|
||||
|
||||
@ -33,7 +33,7 @@ namespace skyline::audio {
|
||||
std::vector<u64> AudioTrack::GetReleasedBuffers(u32 max) {
|
||||
std::vector<u64> bufferIds;
|
||||
|
||||
for (auto index = 0; index < max; index++) {
|
||||
for (u32 index = 0; index < max; index++) {
|
||||
if (!identifiers.back().released)
|
||||
break;
|
||||
bufferIds.push_back(identifiers.back().tag);
|
||||
|
@ -15,11 +15,11 @@ namespace skyline::audio {
|
||||
*/
|
||||
class AudioTrack {
|
||||
private:
|
||||
const std::function<void()> releaseCallback; //!< Callback called when a buffer has been played
|
||||
std::function<void()> releaseCallback; //!< Callback called when a buffer has been played
|
||||
std::deque<BufferIdentifier> identifiers; //!< Queue of all appended buffer identifiers
|
||||
|
||||
const u8 channelCount; //!< The amount channels present in the track
|
||||
const u32 sampleRate; //!< The sample rate of the track
|
||||
u8 channelCount; //!< The amount channels present in the track
|
||||
u32 sampleRate; //!< The sample rate of the track
|
||||
|
||||
public:
|
||||
CircularBuffer<i16, constant::SampleRate * constant::ChannelCount * 10> samples; //!< A vector of all appended audio samples
|
||||
@ -33,7 +33,7 @@ namespace skyline::audio {
|
||||
* @param sampleRate The sample rate to use for the track
|
||||
* @param releaseCallback A callback to call when a buffer has been played
|
||||
*/
|
||||
AudioTrack(const u8 channelCount, const u32 sampleRate, const std::function<void()> &releaseCallback);
|
||||
AudioTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback);
|
||||
|
||||
/**
|
||||
* @brief Starts audio playback using data from appended buffers
|
||||
|
@ -64,10 +64,10 @@ namespace skyline {
|
||||
flag.exchange(next);
|
||||
}
|
||||
|
||||
Settings::Settings(const int preferenceFd) {
|
||||
Settings::Settings(int fd) {
|
||||
tinyxml2::XMLDocument pref;
|
||||
|
||||
if (pref.LoadFile(fdopen(preferenceFd, "r")))
|
||||
if (pref.LoadFile(fdopen(fd, "r")))
|
||||
throw exception("TinyXML2 Error: " + std::string(pref.ErrorStr()));
|
||||
|
||||
tinyxml2::XMLElement *elem = pref.LastChild()->FirstChild()->ToElement();
|
||||
@ -120,8 +120,8 @@ namespace skyline {
|
||||
logger->Info("Key: {}, Value: {}, Type: Bool", iter.first, GetBool(iter.first));
|
||||
}
|
||||
|
||||
Logger::Logger(const int logFd, LogLevel configLevel) : configLevel(configLevel) {
|
||||
logFile.__open(logFd, std::ios::app);
|
||||
Logger::Logger(int fd, LogLevel configLevel) : configLevel(configLevel) {
|
||||
logFile.__open(fd, std::ios::app);
|
||||
WriteHeader("Logging started");
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ namespace skyline {
|
||||
logFile << "0|" << str << "\n";
|
||||
}
|
||||
|
||||
void Logger::Write(const LogLevel level, std::string str) {
|
||||
void Logger::Write(LogLevel level, std::string str) {
|
||||
syslog(levelSyslog[static_cast<u8>(level)], "%s", str.c_str());
|
||||
|
||||
for (auto &character : str)
|
||||
|
@ -26,16 +26,15 @@ namespace skyline {
|
||||
|
||||
namespace constant {
|
||||
// Memory
|
||||
constexpr auto BaseAddress = 0x8000000; //!< The address space base
|
||||
constexpr auto DefStackSize = 0x1E8480; //!< The default amount of stack: 2 MB
|
||||
// Kernel
|
||||
constexpr std::pair<int8_t, int8_t> AndroidPriority = {19, -8}; //!< The range of priority for Android
|
||||
constexpr std::pair<u8, u8> SwitchPriority = {0, 63}; //!< The range of priority for the Nintendo Switch
|
||||
constexpr u64 BaseAddress = 0x8000000; //!< The address space base
|
||||
constexpr u64 DefStackSize = 0x1E8480; //!< The default amount of stack: 2 MB
|
||||
// Display
|
||||
constexpr auto HandheldResolutionW = 1280; //!< The width component of the handheld resolution
|
||||
constexpr auto HandheldResolutionH = 720; //!< The height component of the handheld resolution
|
||||
constexpr auto DockedResolutionW = 1920; //!< The width component of the docked resolution
|
||||
constexpr auto DockedResolutionH = 1080; //!< The height component of the docked resolution
|
||||
constexpr u16 HandheldResolutionW = 1280; //!< The width component of the handheld resolution
|
||||
constexpr u16 HandheldResolutionH = 720; //!< The height component of the handheld resolution
|
||||
constexpr u16 DockedResolutionW = 1920; //!< The width component of the docked resolution
|
||||
constexpr u16 DockedResolutionH = 1080; //!< The height component of the docked resolution
|
||||
// Time
|
||||
constexpr u64 NsInSecond = 1000000000; //!< This is the amount of nanoseconds in a second
|
||||
// Status codes
|
||||
namespace status {
|
||||
constexpr u32 Success = 0x0; //!< "Success"
|
||||
@ -74,13 +73,12 @@ namespace skyline {
|
||||
* @return The current time in nanoseconds
|
||||
*/
|
||||
inline u64 GetTimeNs() {
|
||||
constexpr uint64_t nsInSecond = 1000000000;
|
||||
static u64 frequency{};
|
||||
if (!frequency)
|
||||
asm("MRS %0, CNTFRQ_EL0" : "=r"(frequency));
|
||||
u64 ticks;
|
||||
asm("MRS %0, CNTVCT_EL0" : "=r"(ticks));
|
||||
return ((ticks / frequency) * nsInSecond) + (((ticks % frequency) * nsInSecond + (frequency / 2)) / frequency);
|
||||
return ((ticks / frequency) * constant::NsInSecond) + (((ticks % frequency) * constant::NsInSecond + (frequency / 2)) / frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,19 +112,28 @@ namespace skyline {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param address The address to check for alignment
|
||||
* @return If the address is page aligned
|
||||
* @param value The value to check for alignment
|
||||
* @param multiple The multiple to check alignment with
|
||||
* @return If the address is aligned with the multiple
|
||||
*/
|
||||
constexpr inline bool PageAligned(u64 address) {
|
||||
return !(address & (PAGE_SIZE - 1U));
|
||||
constexpr inline bool IsAligned(u64 value, u64 multiple) {
|
||||
return !(value & (multiple - 1U));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param address The address to check for alignment
|
||||
* @return If the address is word aligned
|
||||
* @param value The value to check for alignment
|
||||
* @return If the value is page aligned
|
||||
*/
|
||||
constexpr inline bool WordAligned(u64 address) {
|
||||
return !(address & 3U);
|
||||
constexpr inline bool PageAligned(u64 value) {
|
||||
return IsAligned(value, PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value The value to check for alignment
|
||||
* @return If the value is word aligned
|
||||
*/
|
||||
constexpr inline bool WordAligned(u64 value) {
|
||||
return IsAligned(value, WORD_BIT / 8);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -222,10 +229,10 @@ namespace skyline {
|
||||
LogLevel configLevel; //!< The level of logs to write
|
||||
|
||||
/**
|
||||
* @param logFd A FD to the log file
|
||||
* @param fd A FD to the log file
|
||||
* @param configLevel The minimum level of logs to write
|
||||
*/
|
||||
Logger(const int logFd, LogLevel configLevel);
|
||||
Logger(int fd, LogLevel configLevel);
|
||||
|
||||
/**
|
||||
* @brief Writes the termination message to the log file
|
||||
@ -243,7 +250,7 @@ namespace skyline {
|
||||
* @param level The level of the log
|
||||
* @param str The value to be written
|
||||
*/
|
||||
void Write(const LogLevel level, std::string str);
|
||||
void Write(LogLevel level, std::string str);
|
||||
|
||||
/**
|
||||
* @brief Write an error log with libfmt formatting
|
||||
@ -305,9 +312,9 @@ namespace skyline {
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param preferenceFd An FD to the preference XML file
|
||||
* @param fd An FD to the preference XML file
|
||||
*/
|
||||
Settings(const int preferenceFd);
|
||||
Settings(int fd);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a particular setting as a string
|
||||
|
@ -62,8 +62,8 @@ namespace skyline::gpu {
|
||||
if (frameTimestamp) {
|
||||
auto now = util::GetTimeNs();
|
||||
|
||||
frametime = static_cast<u32>((now - frameTimestamp) / 10000); // frametime / 100 is the real ms value, this is to retain the first two decimals
|
||||
fps = static_cast<u16>(1000000000 / (now - frameTimestamp));
|
||||
frametime = static_cast<u32>((now - frameTimestamp) / (constant::NsInSecond / 100)); // frametime / 100 is the real ms value, this is to retain the first two decimals
|
||||
fps = static_cast<u16>(constant::NsInSecond / (now - frameTimestamp));
|
||||
|
||||
frameTimestamp = now;
|
||||
} else {
|
||||
|
13
app/src/main/cpp/skyline/gpu/format.h
Normal file
13
app/src/main/cpp/skyline/gpu/format.h
Normal file
@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
namespace skyline::gpu::format {
|
||||
using Format = gpu::texture::Format;
|
||||
|
||||
constexpr Format RGBA8888Unorm{sizeof(u8) * 4, 1, 1, vk::Format::eR8G8B8A8Unorm}; //!< 8-bits per channel 4-channel pixels
|
||||
constexpr Format RGB565Unorm{sizeof(u8) * 2, 1, 1, vk::Format::eR5G6B5UnormPack16}; //!< Red channel: 5-bit, Green channel: 6-bit, Blue channel: 5-bit
|
||||
}
|
@ -20,10 +20,10 @@ namespace skyline::gpu {
|
||||
|
||||
if (guest->tileMode == texture::TileMode::Block) {
|
||||
// Reference on Block-linear tiling: https://gist.github.com/PixelyIon/d9c35050af0ef5690566ca9f0965bc32
|
||||
constexpr auto sectorWidth = 16; // The width of a sector in bytes
|
||||
constexpr auto sectorHeight = 2; // The height of a sector in lines
|
||||
constexpr auto gobWidth = 64; // The width of a GOB in bytes
|
||||
constexpr auto gobHeight = 8; // The height of a GOB in lines
|
||||
constexpr u8 sectorWidth = 16; // The width of a sector in bytes
|
||||
constexpr u8 sectorHeight = 2; // The height of a sector in lines
|
||||
constexpr u8 gobWidth = 64; // The width of a GOB in bytes
|
||||
constexpr u8 gobHeight = 8; // The height of a GOB in lines
|
||||
|
||||
auto robHeight = gobHeight * guest->tileConfig.blockHeight; // The height of a single ROB (Row of Blocks) in lines
|
||||
auto surfaceHeightRobs = util::AlignUp(dimensions.height / format.blockHeight, robHeight) / robHeight; // The height of the surface in ROBs (Row Of Blocks)
|
||||
@ -41,8 +41,8 @@ namespace skyline::gpu {
|
||||
auto outputGob = outputBlock; // We iterate through a GOB independently of the block
|
||||
for (u32 gobY = 0; gobY < guest->tileConfig.blockHeight; gobY++) { // Every Block contains `blockHeight` Y-axis GOBs
|
||||
for (u32 index = 0; index < sectorWidth * sectorHeight; index++) { // Every Y-axis GOB contains `sectorWidth * sectorHeight` sectors
|
||||
const u32 xT = ((index << 3) & 0b10000) | ((index << 1) & 0b100000); // Morton-Swizzle on the X-axis
|
||||
const u32 yT = ((index >> 1) & 0b110) | (index & 0b1); // Morton-Swizzle on the Y-axis
|
||||
u32 xT = ((index << 3) & 0b10000) | ((index << 1) & 0b100000); // Morton-Swizzle on the X-axis
|
||||
u32 yT = ((index >> 1) & 0b110) | (index & 0b1); // Morton-Swizzle on the Y-axis
|
||||
std::memcpy(outputGob + (yT * robWidthBytes) + xT, inputSector, sectorWidth);
|
||||
inputSector += sectorWidth; // `sectorWidth` bytes are of sequential image data
|
||||
}
|
||||
@ -59,7 +59,7 @@ namespace skyline::gpu {
|
||||
auto inputLine = texture; // The address of the input line
|
||||
auto outputLine = output; // The address of the output line
|
||||
|
||||
for (auto line = 0; line < dimensions.height; line++) {
|
||||
for (u32 line = 0; line < dimensions.height; line++) {
|
||||
std::memcpy(outputLine, inputLine, sizeLine);
|
||||
inputLine += sizeStride;
|
||||
outputLine += sizeLine;
|
||||
|
@ -97,11 +97,6 @@ namespace skyline {
|
||||
}
|
||||
};
|
||||
|
||||
namespace format {
|
||||
constexpr Format RGBA8888Unorm{sizeof(u8) * 4, 1, 1, vk::Format::eR8G8B8A8Unorm}; //!< 8-bits per channel 4-channel pixels
|
||||
constexpr Format RGB565Unorm{sizeof(u8) * 2, 1, 1, vk::Format::eR5G6B5UnormPack16}; //!< Red channel: 5-bit, Green channel: 6-bit, Blue channel: 5-bit
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This describes the linearity of a texture. Refer to Chapter 20.1 of the Tegra X1 TRM for information.
|
||||
*/
|
||||
|
@ -125,14 +125,14 @@ namespace skyline {
|
||||
/**
|
||||
* @return The address of the buffer
|
||||
*/
|
||||
inline u64 Address() const {
|
||||
inline u64 Address() {
|
||||
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The buffer counter
|
||||
* @return The counter index of the buffer
|
||||
*/
|
||||
inline u16 Counter() const {
|
||||
inline u16 Counter() {
|
||||
return static_cast<u16>(counter0_5) | static_cast<u16>(counter9_11) << 9;
|
||||
}
|
||||
};
|
||||
@ -161,14 +161,14 @@ namespace skyline {
|
||||
/**
|
||||
* @return The address of the buffer
|
||||
*/
|
||||
inline u64 Address() const {
|
||||
inline u64 Address() {
|
||||
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The size of the buffer
|
||||
*/
|
||||
inline u64 Size() const {
|
||||
inline u64 Size() {
|
||||
return static_cast<u64>(size0_31) | static_cast<u64>(size32_35) << 32;
|
||||
}
|
||||
};
|
||||
|
@ -92,7 +92,7 @@ namespace skyline::kernel {
|
||||
chunk->size = size;
|
||||
}
|
||||
|
||||
void MemoryManager::InsertBlock(ChunkDescriptor *chunk, const BlockDescriptor block) {
|
||||
void MemoryManager::InsertBlock(ChunkDescriptor *chunk, BlockDescriptor block) {
|
||||
if (chunk->address + chunk->size < block.address + block.size)
|
||||
throw exception("InsertBlock: Inserting block past chunk end is not allowed");
|
||||
|
||||
@ -118,7 +118,7 @@ namespace skyline::kernel {
|
||||
throw exception("InsertBlock: Block offset not present within current block list");
|
||||
}
|
||||
|
||||
void MemoryManager::InitializeRegions(u64 address, u64 size, const memory::AddressSpaceType type) {
|
||||
void MemoryManager::InitializeRegions(u64 address, u64 size, memory::AddressSpaceType type) {
|
||||
switch (type) {
|
||||
case memory::AddressSpaceType::AddressSpace32Bit:
|
||||
throw exception("32-bit address spaces are not supported");
|
||||
|
@ -16,29 +16,29 @@ namespace skyline {
|
||||
/**
|
||||
* @brief This constructor initializes all permissions to false
|
||||
*/
|
||||
Permission() : r(), w(), x() {};
|
||||
constexpr Permission() : r(), w(), x() {}
|
||||
|
||||
/**
|
||||
* @param read If memory has read permission
|
||||
* @param write If memory has write permission
|
||||
* @param execute If memory has execute permission
|
||||
*/
|
||||
Permission(bool read, bool write, bool execute) : r(read), w(write), x(execute) {};
|
||||
constexpr Permission(bool read, bool write, bool execute) : r(read), w(write), x(execute) {}
|
||||
|
||||
/**
|
||||
* @brief Equality operator between two Permission objects
|
||||
*/
|
||||
inline bool operator==(const Permission &rhs) const { return (this->r == rhs.r && this->w == rhs.w && this->x == rhs.x); };
|
||||
inline bool operator==(const Permission &rhs) const { return (this->r == rhs.r && this->w == rhs.w && this->x == rhs.x); }
|
||||
|
||||
/**
|
||||
* @brief Inequality operator between two Permission objects
|
||||
*/
|
||||
inline bool operator!=(const Permission &rhs) const { return !operator==(rhs); };
|
||||
inline bool operator!=(const Permission &rhs) const { return !operator==(rhs); }
|
||||
|
||||
/**
|
||||
* @return The value of the permission struct in Linux format
|
||||
*/
|
||||
int Get() const {
|
||||
constexpr int Get() const {
|
||||
int perm = 0;
|
||||
if (r)
|
||||
perm |= PROT_READ;
|
||||
@ -47,7 +47,7 @@ namespace skyline {
|
||||
if (x)
|
||||
perm |= PROT_EXEC;
|
||||
return perm;
|
||||
};
|
||||
}
|
||||
|
||||
bool r; //!< The permission to read
|
||||
bool w; //!< The permission to write
|
||||
@ -114,9 +114,9 @@ namespace skyline {
|
||||
* @brief This structure is used to hold the state of a certain block of memory (https://switchbrew.org/wiki/SVC#MemoryState)
|
||||
*/
|
||||
union MemoryState {
|
||||
constexpr MemoryState(const u32 value) : value(value) {};
|
||||
constexpr MemoryState(const u32 value) : value(value) {}
|
||||
|
||||
constexpr MemoryState() : value(0) {};
|
||||
constexpr MemoryState() : value(0) {}
|
||||
|
||||
struct {
|
||||
MemoryType type; //!< The MemoryType of this memory block
|
||||
@ -304,9 +304,9 @@ namespace skyline {
|
||||
/**
|
||||
* @brief Insert a block into a chunk
|
||||
* @param chunk The chunk to insert the block into
|
||||
* @param block The block to insert
|
||||
* @param block The block to insert into the chunk
|
||||
*/
|
||||
static void InsertBlock(ChunkDescriptor *chunk, const BlockDescriptor block);
|
||||
static void InsertBlock(ChunkDescriptor *chunk, BlockDescriptor block);
|
||||
|
||||
/**
|
||||
* @brief This initializes all of the regions in the address space
|
||||
@ -314,7 +314,7 @@ namespace skyline {
|
||||
* @param size The size of the code region
|
||||
* @param type The type of the address space
|
||||
*/
|
||||
void InitializeRegions(u64 address, u64 size, const memory::AddressSpaceType type);
|
||||
void InitializeRegions(u64 address, u64 size, memory::AddressSpaceType type);
|
||||
|
||||
public:
|
||||
friend class type::KPrivateMemory;
|
||||
|
@ -6,10 +6,9 @@
|
||||
|
||||
namespace skyline::kernel::svc {
|
||||
void SetHeapSize(DeviceState &state) {
|
||||
constexpr auto heapSizeAlign = 0x200000; // The heap size has to be a multiple of this value
|
||||
auto size = state.ctx->registers.w1;
|
||||
|
||||
if (size % heapSizeAlign != 0) {
|
||||
if (!util::IsAligned(size, 0x200000)) {
|
||||
state.ctx->registers.w0 = constant::status::InvSize;
|
||||
state.ctx->registers.x1 = 0;
|
||||
|
||||
@ -219,19 +218,19 @@ namespace skyline::kernel::svc {
|
||||
}
|
||||
|
||||
void CreateThread(DeviceState &state) {
|
||||
u64 entryAddress = state.ctx->registers.x1;
|
||||
u64 entryArgument = state.ctx->registers.x2;
|
||||
u64 stackTop = state.ctx->registers.x3;
|
||||
u8 priority = static_cast<u8>(state.ctx->registers.w4);
|
||||
auto entryAddress = state.ctx->registers.x1;
|
||||
auto entryArgument = state.ctx->registers.x2;
|
||||
auto stackTop = state.ctx->registers.x3;
|
||||
auto priority = static_cast<i8>(state.ctx->registers.w4);
|
||||
|
||||
if ((priority < constant::SwitchPriority.first) || (priority > constant::SwitchPriority.second)) {
|
||||
if (!state.thread->switchPriority.Valid(priority)) {
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority);
|
||||
return;
|
||||
}
|
||||
|
||||
auto thread = state.process->CreateThread(entryAddress, entryArgument, stackTop, priority);
|
||||
state.logger->Debug("svcCreateThread: Created thread with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, PID: {})", thread->handle, entryAddress, entryArgument, stackTop, priority, thread->tid);
|
||||
state.logger->Debug("svcCreateThread: Created thread with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, TID: {})", thread->handle, entryAddress, entryArgument, stackTop, priority, thread->tid);
|
||||
|
||||
state.ctx->registers.w1 = thread->handle;
|
||||
state.ctx->registers.w0 = constant::status::Success;
|
||||
@ -305,7 +304,7 @@ namespace skyline::kernel::svc {
|
||||
void MapSharedMemory(DeviceState &state) {
|
||||
try {
|
||||
auto object = state.process->GetHandle<type::KSharedMemory>(state.ctx->registers.w0);
|
||||
u64 address = state.ctx->registers.x1;
|
||||
auto address = state.ctx->registers.x1;
|
||||
|
||||
if (!util::PageAligned(address)) {
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
@ -320,8 +319,7 @@ namespace skyline::kernel::svc {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 perm = state.ctx->registers.w3;
|
||||
memory::Permission permission = *reinterpret_cast<memory::Permission *>(&perm);
|
||||
memory::Permission permission = *reinterpret_cast<memory::Permission *>(&state.ctx->registers.w3);
|
||||
if ((permission.w && !permission.r) || (permission.x && !permission.r)) {
|
||||
state.logger->Warn("svcMapSharedMemory: 'permission' invalid: {}{}{}", permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-");
|
||||
state.ctx->registers.w0 = constant::status::InvPermission;
|
||||
@ -340,22 +338,21 @@ namespace skyline::kernel::svc {
|
||||
}
|
||||
|
||||
void CreateTransferMemory(DeviceState &state) {
|
||||
u64 address = state.ctx->registers.x1;
|
||||
auto address = state.ctx->registers.x1;
|
||||
if (!util::PageAligned(address)) {
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
state.logger->Warn("svcCreateTransferMemory: 'address' not page aligned: 0x{:X}", address);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 size = state.ctx->registers.x2;
|
||||
auto size = state.ctx->registers.x2;
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->registers.w0 = constant::status::InvSize;
|
||||
state.logger->Warn("svcCreateTransferMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 perm = state.ctx->registers.w3;
|
||||
memory::Permission permission = *reinterpret_cast<memory::Permission *>(&perm);
|
||||
memory::Permission permission = *reinterpret_cast<memory::Permission *>(&state.ctx->registers.w3);
|
||||
if ((permission.w && !permission.r) || (permission.x && !permission.r)) {
|
||||
state.logger->Warn("svcCreateTransferMemory: 'permission' invalid: {}{}{}", permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-");
|
||||
state.ctx->registers.w0 = constant::status::InvPermission;
|
||||
@ -387,11 +384,11 @@ namespace skyline::kernel::svc {
|
||||
try {
|
||||
auto &object = state.process->handles.at(handle);
|
||||
switch (object->objectType) {
|
||||
case (type::KType::KEvent):
|
||||
case type::KType::KEvent:
|
||||
std::static_pointer_cast<type::KEvent>(object)->ResetSignal();
|
||||
break;
|
||||
|
||||
case (type::KType::KProcess):
|
||||
case type::KType::KProcess:
|
||||
std::static_pointer_cast<type::KProcess>(object)->ResetSignal();
|
||||
break;
|
||||
|
||||
|
@ -27,7 +27,7 @@ namespace skyline::kernel::type {
|
||||
* @param size The size of the partition to change the permissions of
|
||||
* @param permission The new permissions to be set for the memory
|
||||
*/
|
||||
virtual void UpdatePermission(const u64 address, const u64 size, memory::Permission permission) = 0;
|
||||
virtual void UpdatePermission(u64 address, u64 size, memory::Permission permission) = 0;
|
||||
|
||||
/**
|
||||
* @brief Updates the permissions of a chunk of mapped memory
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "KProcess.h"
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, const memory::MemoryState memState) : size(size), KMemory(state, KType::KPrivateMemory) {
|
||||
KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, memory::MemoryState memState) : size(size), KMemory(state, KType::KPrivateMemory) {
|
||||
if (address && !util::PageAligned(address))
|
||||
throw exception("KPrivateMemory was created with non-page-aligned address: 0x{:X}", address);
|
||||
|
||||
@ -113,7 +113,7 @@ namespace skyline::kernel::type {
|
||||
size = nSize;
|
||||
}
|
||||
|
||||
void KPrivateMemory::UpdatePermission(const u64 address, const u64 size, memory::Permission permission) {
|
||||
void KPrivateMemory::UpdatePermission(u64 address, u64 size, memory::Permission permission) {
|
||||
Registers fregs{
|
||||
.x0 = address,
|
||||
.x1 = size,
|
||||
|
@ -24,7 +24,7 @@ namespace skyline::kernel::type {
|
||||
* @param permission The permissions for the allocated memory
|
||||
* @param memState The MemoryState of the chunk of memory
|
||||
*/
|
||||
KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, const memory::MemoryState memState);
|
||||
KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, memory::MemoryState memState);
|
||||
|
||||
/**
|
||||
* @brief Remap a chunk of memory as to change the size occupied by it
|
||||
@ -39,7 +39,7 @@ namespace skyline::kernel::type {
|
||||
* @param size The size of the partition to change the permissions of
|
||||
* @param permission The new permissions to be set for the memory
|
||||
*/
|
||||
virtual void UpdatePermission(const u64 address, const u64 size, memory::Permission permission);
|
||||
virtual void UpdatePermission(u64 address, u64 size, memory::Permission permission);
|
||||
|
||||
/**
|
||||
* @brief Updates the permissions of a chunk of mapped memory
|
||||
|
@ -78,7 +78,7 @@ namespace skyline::kernel::type {
|
||||
status = Status::Exiting;
|
||||
}
|
||||
|
||||
std::shared_ptr<KThread> KProcess::CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority) {
|
||||
std::shared_ptr<KThread> KProcess::CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, i8 priority) {
|
||||
auto size = (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
|
||||
auto tlsMem = std::make_shared<type::KSharedMemory>(state, 0, size, memory::Permission{true, true, false}, memory::states::Reserved);
|
||||
|
||||
@ -102,12 +102,12 @@ namespace skyline::kernel::type {
|
||||
return process;
|
||||
}
|
||||
|
||||
u64 KProcess::GetHostAddress(u64 address) const {
|
||||
u64 KProcess::GetHostAddress(u64 address) {
|
||||
auto chunk = state.os->memory.GetChunk(address);
|
||||
return (chunk && chunk->host) ? chunk->host + (address - chunk->address) : 0;
|
||||
}
|
||||
|
||||
void KProcess::ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest) const {
|
||||
void KProcess::ReadMemory(void *destination, u64 offset, size_t size, bool forceGuest) {
|
||||
if (!forceGuest) {
|
||||
auto source = GetHostAddress(offset);
|
||||
|
||||
@ -131,7 +131,7 @@ namespace skyline::kernel::type {
|
||||
pread64(memFd, destination, size, offset);
|
||||
}
|
||||
|
||||
void KProcess::WriteMemory(const void *source, const u64 offset, const size_t size, const bool forceGuest) const {
|
||||
void KProcess::WriteMemory(const void *source, u64 offset, size_t size, bool forceGuest) {
|
||||
if (!forceGuest) {
|
||||
auto destination = GetHostAddress(offset);
|
||||
|
||||
@ -155,7 +155,7 @@ namespace skyline::kernel::type {
|
||||
pwrite64(memFd, source, size, offset);
|
||||
}
|
||||
|
||||
void KProcess::CopyMemory(u64 source, u64 destination, size_t size) const {
|
||||
void KProcess::CopyMemory(u64 source, u64 destination, size_t size) {
|
||||
auto sourceHost = GetHostAddress(source);
|
||||
auto destinationHost = GetHostAddress(destination);
|
||||
|
||||
|
@ -146,14 +146,14 @@ namespace skyline {
|
||||
* @param priority The priority of the thread
|
||||
* @return An instance of KThread class for the corresponding thread
|
||||
*/
|
||||
std::shared_ptr<KThread> CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority);
|
||||
std::shared_ptr<KThread> CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, i8 priority);
|
||||
|
||||
/**
|
||||
* @brief This returns the host address for a specific address in guest memory
|
||||
* @param address The corresponding guest address
|
||||
* @return The corresponding host address
|
||||
*/
|
||||
u64 GetHostAddress(const u64 address) const;
|
||||
u64 GetHostAddress(u64 address);
|
||||
|
||||
/**
|
||||
* @tparam Type The type of the pointer to return
|
||||
@ -162,7 +162,7 @@ namespace skyline {
|
||||
* @note This can return a nullptr if the address is invalid
|
||||
*/
|
||||
template<typename Type>
|
||||
inline Type *GetPointer(const u64 address) const {
|
||||
inline Type *GetPointer(u64 address) {
|
||||
return reinterpret_cast<Type *>(GetHostAddress(address));
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ namespace skyline {
|
||||
* @return A reference to object with type T
|
||||
*/
|
||||
template<typename Type>
|
||||
inline Type &GetReference(u64 address) const {
|
||||
inline Type &GetReference(u64 address) {
|
||||
auto source = GetPointer<Type>(address);
|
||||
if (source)
|
||||
return *source;
|
||||
@ -188,7 +188,7 @@ namespace skyline {
|
||||
* @return A copy of the object from guest memory
|
||||
*/
|
||||
template<typename Type>
|
||||
inline Type GetObject(u64 address) const {
|
||||
inline Type GetObject(u64 address) {
|
||||
auto source = GetPointer<Type>(address);
|
||||
if (source) {
|
||||
return *source;
|
||||
@ -205,7 +205,7 @@ namespace skyline {
|
||||
* @param maxSize The maximum size of the string
|
||||
* @return A copy of a string in guest memory
|
||||
*/
|
||||
inline std::string GetString(u64 address, const size_t maxSize) const {
|
||||
inline std::string GetString(u64 address, size_t maxSize) {
|
||||
auto source = GetPointer<char>(address);
|
||||
if (source)
|
||||
return std::string(source, maxSize);
|
||||
@ -221,7 +221,7 @@ namespace skyline {
|
||||
* @param address The address of the object
|
||||
*/
|
||||
template<typename Type>
|
||||
inline void WriteMemory(Type &item, u64 address) const {
|
||||
inline void WriteMemory(Type &item, u64 address) {
|
||||
auto destination = GetPointer<Type>(address);
|
||||
if (destination) {
|
||||
*destination = item;
|
||||
@ -237,7 +237,7 @@ namespace skyline {
|
||||
* @param address The address of the object
|
||||
*/
|
||||
template<typename Type>
|
||||
inline void WriteMemory(const Type &item, u64 address) const {
|
||||
inline void WriteMemory(const Type &item, u64 address) {
|
||||
auto destination = GetPointer<Type>(address);
|
||||
if (destination) {
|
||||
*destination = item;
|
||||
@ -253,7 +253,7 @@ namespace skyline {
|
||||
* @param size The amount of memory to be read
|
||||
* @param forceGuest This flag forces the write to be performed in guest address space
|
||||
*/
|
||||
void ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest = false) const;
|
||||
void ReadMemory(void *destination, u64 offset, size_t size, bool forceGuest = false);
|
||||
|
||||
/**
|
||||
* @brief Write to the guest's memory
|
||||
@ -262,7 +262,7 @@ namespace skyline {
|
||||
* @param size The amount of memory to be written
|
||||
* @param forceGuest This flag forces the write to be performed in guest address space
|
||||
*/
|
||||
void WriteMemory(const void *source, const u64 offset, const size_t size, const bool forceGuest = false) const;
|
||||
void WriteMemory(const void *source, u64 offset, size_t size, bool forceGuest = false);
|
||||
|
||||
/**
|
||||
* @brief Copy one chunk to another in the guest's memory
|
||||
@ -270,7 +270,7 @@ namespace skyline {
|
||||
* @param destination The address to write the read data to
|
||||
* @param size The amount of memory to be copied
|
||||
*/
|
||||
void CopyMemory(const u64 source, const u64 destination, const size_t size) const;
|
||||
void CopyMemory(u64 source, u64 destination, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Creates a new handle to a KObject and adds it to the process handle_table
|
||||
|
@ -13,10 +13,10 @@ namespace skyline::kernel::type {
|
||||
*/
|
||||
class KSession : public KSyncObject {
|
||||
public:
|
||||
const std::shared_ptr<service::BaseService> serviceObject; //!< A shared pointer to the service class
|
||||
std::shared_ptr<service::BaseService> serviceObject; //!< A shared pointer to the service class
|
||||
std::unordered_map<KHandle, std::shared_ptr<service::BaseService>> domainTable; //!< This maps from a virtual handle to it's service
|
||||
KHandle handleIndex{0x1}; //!< The currently allocated handle index
|
||||
const service::Service serviceType; //!< The type of the service
|
||||
service::Service serviceType; //!< The type of the service
|
||||
enum class ServiceStatus { Open, Closed } serviceStatus{ServiceStatus::Open}; //!< If the session is open or closed
|
||||
bool isDomain{}; //!< Holds if this is a domain session or not
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "KProcess.h"
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState, int mmapFlags) : initialState(memState), KMemory(state, KType::KSharedMemory) {
|
||||
KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, memory::MemoryState memState, int mmapFlags) : initialState(memState), KMemory(state, KType::KSharedMemory) {
|
||||
if (address && !util::PageAligned(address))
|
||||
throw exception("KSharedMemory was created with non-page-aligned address: 0x{:X}", address);
|
||||
|
||||
|
@ -38,7 +38,7 @@ namespace skyline::kernel::type {
|
||||
* @param memState The MemoryState of the chunk of memory
|
||||
* @param mmapFlags Additional flags to pass to mmap
|
||||
*/
|
||||
KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::states::SharedMemory, int mmapFlags = 0);
|
||||
KSharedMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, memory::MemoryState memState = memory::states::SharedMemory, int mmapFlags = 0);
|
||||
|
||||
/**
|
||||
* @brief Maps the shared memory in the guest
|
||||
@ -47,7 +47,7 @@ namespace skyline::kernel::type {
|
||||
* @param permission The permission of the kernel process
|
||||
* @return The address of the allocation
|
||||
*/
|
||||
u64 Map(const u64 address, const u64 size, memory::Permission permission);
|
||||
u64 Map(u64 address, u64 size, memory::Permission permission);
|
||||
|
||||
/**
|
||||
* @brief Resize a chunk of memory as to change the size occupied by it
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include "KProcess.h"
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KThread::KThread(const DeviceState &state, KHandle handle, pid_t selfTid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr<type::KSharedMemory> &tlsMemory)
|
||||
: handle(handle), tid(selfTid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state, KType::KThread) {
|
||||
KThread::KThread(const DeviceState &state, KHandle handle, pid_t selfTid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, i8 priority, KProcess *parent, const std::shared_ptr<type::KSharedMemory> &tlsMemory) : handle(handle), tid(selfTid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state,
|
||||
KType::KThread) {
|
||||
UpdatePriority(priority);
|
||||
}
|
||||
|
||||
@ -30,16 +30,16 @@ namespace skyline::kernel::type {
|
||||
if (status != Status::Dead) {
|
||||
status = Status::Dead;
|
||||
Signal();
|
||||
tgkill(parent->pid, tid, SIGKILL);
|
||||
|
||||
tgkill(parent->pid, tid, SIGTERM);
|
||||
}
|
||||
}
|
||||
|
||||
void KThread::UpdatePriority(u8 priority) {
|
||||
void KThread::UpdatePriority(i8 priority) {
|
||||
this->priority = priority;
|
||||
auto linuxPriority =
|
||||
static_cast<int8_t>(constant::AndroidPriority.first + ((static_cast<float>(constant::AndroidPriority.second - constant::AndroidPriority.first) / static_cast<float>(constant::SwitchPriority.second - constant::SwitchPriority.first)) * (static_cast<float>(priority) - constant::SwitchPriority.first))); // Resize range SwitchPriority (Nintendo Priority) to AndroidPriority (Android Priority)
|
||||
auto priorityValue = androidPriority.Rescale(switchPriority, priority);
|
||||
|
||||
if (setpriority(PRIO_PROCESS, static_cast<id_t>(tid), linuxPriority) == -1)
|
||||
throw exception("Couldn't set process priority to {} for PID: {}", linuxPriority, tid);
|
||||
if (setpriority(PRIO_PROCESS, static_cast<id_t>(tid), priorityValue) == -1)
|
||||
throw exception("Couldn't set process priority to {} for PID: {}", priorityValue, tid);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,31 @@ namespace skyline::kernel::type {
|
||||
u64 entryPoint; //!< The address to start execution at
|
||||
u64 entryArg; //!< An argument to pass to the process on entry
|
||||
|
||||
/**
|
||||
* @brief This holds a range of priorities for a corresponding system
|
||||
*/
|
||||
struct Priority {
|
||||
i8 low; //!< The low range of priority
|
||||
i8 high; //!< The high range of priority
|
||||
|
||||
/**
|
||||
* @param priority The priority range of the value
|
||||
* @param value The priority value to rescale
|
||||
* @return The rescaled priority value according to this range
|
||||
*/
|
||||
constexpr inline i8 Rescale(const Priority &priority, i8 value) {
|
||||
return static_cast<i8>(priority.low + ((static_cast<float>(priority.high - priority.low) / static_cast<float>(priority.low - priority.high)) * (static_cast<float>(value) - priority.low)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value The priority value to check for validity
|
||||
* @return If the supplied priority value is valid
|
||||
*/
|
||||
constexpr inline bool Valid(i8 value) {
|
||||
return (value >= low) && (value <= high);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
enum class Status {
|
||||
Created, //!< The thread has been created but has not been started yet
|
||||
@ -28,7 +53,10 @@ namespace skyline::kernel::type {
|
||||
pid_t tid; //!< The TID of the current thread
|
||||
u64 stackTop; //!< The top of the stack (Where it starts growing downwards from)
|
||||
u64 tls; //!< The address of TLS (Thread Local Storage) slot assigned to the current thread
|
||||
u8 priority; //!< The priority of a thread in Nintendo format
|
||||
i8 priority; //!< The priority of a thread in Nintendo format
|
||||
|
||||
Priority androidPriority{19, -8}; //!< The range of priorities for Android
|
||||
Priority switchPriority{0, 63}; //!< The range of priorities for the Nintendo Switch
|
||||
|
||||
/**
|
||||
* @param state The state of the device
|
||||
@ -42,7 +70,7 @@ namespace skyline::kernel::type {
|
||||
* @param parent The parent process of this thread
|
||||
* @param tlsMemory The KSharedMemory object for TLS memory allocated by the guest process
|
||||
*/
|
||||
KThread(const DeviceState &state, KHandle handle, pid_t selfTid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr<type::KSharedMemory> &tlsMemory);
|
||||
KThread(const DeviceState &state, KHandle handle, pid_t selfTid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, i8 priority, KProcess *parent, const std::shared_ptr<type::KSharedMemory> &tlsMemory);
|
||||
|
||||
/**
|
||||
* @brief Kills the thread and deallocates the memory allocated for stack.
|
||||
@ -64,6 +92,6 @@ namespace skyline::kernel::type {
|
||||
* @details Set the priority of the current thread to `priority` using setpriority [https://linux.die.net/man/3/setpriority]. We rescale the priority from Nintendo scale to that of Android.
|
||||
* @param priority The priority of the thread in Nintendo format
|
||||
*/
|
||||
void UpdatePriority(u8 priority);
|
||||
void UpdatePriority(i8 priority);
|
||||
};
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "KTransferMemory.h"
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KTransferMemory::KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState) : host(host), size(size), KMemory(state, KType::KTransferMemory) {
|
||||
KTransferMemory::KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, memory::Permission permission, memory::MemoryState memState) : host(host), size(size), KMemory(state, KType::KTransferMemory) {
|
||||
if (address && !util::PageAligned(address))
|
||||
throw exception("KTransferMemory was created with non-page-aligned address: 0x{:X}", address);
|
||||
|
||||
@ -172,7 +172,7 @@ namespace skyline::kernel::type {
|
||||
}
|
||||
}
|
||||
|
||||
void KTransferMemory::UpdatePermission(const u64 address, const u64 size, memory::Permission permission) {
|
||||
void KTransferMemory::UpdatePermission(u64 address, u64 size, memory::Permission permission) {
|
||||
BlockDescriptor block{
|
||||
.address = address,
|
||||
.size = size,
|
||||
|
@ -26,7 +26,7 @@ namespace skyline::kernel::type {
|
||||
* @param type The type of the memory
|
||||
* @param memState The MemoryState of the chunk of memory
|
||||
*/
|
||||
KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::states::TransferMemory);
|
||||
KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, memory::Permission permission, memory::MemoryState memState = memory::states::TransferMemory);
|
||||
|
||||
/**
|
||||
* @brief Transfers this piece of memory to another process
|
||||
@ -50,7 +50,7 @@ namespace skyline::kernel::type {
|
||||
* @param size The size of the partition to change the permissions of
|
||||
* @param permission The new permissions to be set for the memory
|
||||
*/
|
||||
virtual void UpdatePermission(const u64 address, const u64 size, memory::Permission permission);
|
||||
virtual void UpdatePermission(u64 address, u64 size, memory::Permission permission);
|
||||
|
||||
/**
|
||||
* @brief Updates the permissions of a chunk of mapped memory
|
||||
|
@ -10,7 +10,7 @@
|
||||
namespace skyline::loader {
|
||||
class Loader {
|
||||
protected:
|
||||
const int romFd; //!< An FD to the ROM file
|
||||
int fd; //!< An FD to the ROM file
|
||||
|
||||
/**
|
||||
* @brief Read the file at a particular offset
|
||||
@ -21,14 +21,14 @@ namespace skyline::loader {
|
||||
*/
|
||||
template<typename T>
|
||||
inline void ReadOffset(T *output, u64 offset, size_t size) {
|
||||
pread64(romFd, output, size, offset);
|
||||
pread64(fd, output, size, offset);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param filePath The path to the ROM file
|
||||
*/
|
||||
Loader(const int romFd) : romFd(romFd) {}
|
||||
Loader(int fd) : fd(fd) {}
|
||||
|
||||
/**
|
||||
* This loads in the data of the main process
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "nro.h"
|
||||
|
||||
namespace skyline::loader {
|
||||
NroLoader::NroLoader(const int romFd) : Loader(romFd) {
|
||||
NroLoader::NroLoader(int fd) : Loader(fd) {
|
||||
ReadOffset((u32 *) &header, 0x0, sizeof(NroHeader));
|
||||
|
||||
if (header.magic != util::MakeMagic<u32>("NRO0"))
|
||||
@ -27,6 +27,10 @@ namespace skyline::loader {
|
||||
u64 textSize = text.size();
|
||||
u64 rodataSize = rodata.size();
|
||||
u64 dataSize = data.size();
|
||||
|
||||
if (!util::IsAligned(textSize, PAGE_SIZE) || !util::IsAligned(rodataSize, PAGE_SIZE) || !util::IsAligned(dataSize, PAGE_SIZE))
|
||||
throw exception("LoadProcessData: Sections are not aligned with page size: 0x{:X}, 0x{:X}, 0x{:X}", textSize, rodataSize, dataSize);
|
||||
|
||||
u64 patchSize = patch.size() * sizeof(u32);
|
||||
u64 padding = util::AlignUp(textSize + rodataSize + dataSize + header.bssSize + patchSize, PAGE_SIZE) - (textSize + rodataSize + dataSize + header.bssSize + patchSize);
|
||||
|
||||
|
@ -46,12 +46,12 @@ namespace skyline::loader {
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param filePath The path to the ROM file
|
||||
* @param fd A file descriptor to the ROM
|
||||
*/
|
||||
NroLoader(const int romFd);
|
||||
NroLoader(int fd);
|
||||
|
||||
/**
|
||||
* This loads in the data of the main process
|
||||
* @brief This loads in the data of the main process
|
||||
* @param process The process to load in the data
|
||||
* @param state The state of the device
|
||||
*/
|
||||
|
@ -36,7 +36,7 @@ namespace skyline {
|
||||
if (__predict_false(!Surface))
|
||||
continue;
|
||||
|
||||
const u16 svc = static_cast<const u16>(state.ctx->commandId);
|
||||
auto svc = state.ctx->svc;
|
||||
|
||||
try {
|
||||
if (kernel::svc::SvcTable[svc]) {
|
||||
@ -51,7 +51,7 @@ namespace skyline {
|
||||
|
||||
state.ctx->state = ThreadState::WaitRun;
|
||||
} else if (__predict_false(state.ctx->state == ThreadState::GuestCrash)) {
|
||||
state.logger->Warn("Thread with PID {} has crashed due to signal: {}", thread, strsignal(state.ctx->commandId));
|
||||
state.logger->Warn("Thread with PID {} has crashed due to signal: {}", thread, strsignal(state.ctx->svc));
|
||||
ThreadTrace();
|
||||
|
||||
state.ctx->state = ThreadState::WaitRun;
|
||||
@ -115,7 +115,7 @@ namespace skyline {
|
||||
* So, we opted to use the hacky solution and disable optimizations for this single function.
|
||||
*/
|
||||
void ExecuteFunctionCtx(ThreadCall call, Registers &funcRegs, ThreadContext *ctx) __attribute__ ((optnone)) {
|
||||
ctx->commandId = static_cast<u32>(call);
|
||||
ctx->threadCall = call;
|
||||
Registers registers = ctx->registers;
|
||||
|
||||
while (ctx->state != ThreadState::WaitInit && ctx->state != ThreadState::WaitKernel);
|
||||
@ -192,9 +192,9 @@ namespace skyline {
|
||||
if (ctx->sp)
|
||||
regStr += fmt::format("\nStack Pointer: 0x{:X}", ctx->sp);
|
||||
|
||||
constexpr auto numRegisters = 31; //!< The amount of general-purpose registers in ARMv8
|
||||
constexpr u8 numRegisters = 31; //!< The amount of general-purpose registers in ARMv8
|
||||
|
||||
for (u16 index = 0; index < numRegisters - 2; index += 2) {
|
||||
for (u8 index = 0; index < numRegisters - 2; index += 2) {
|
||||
auto xStr = index < 10 ? " X" : "X";
|
||||
regStr += fmt::format("\n{}{}: 0x{:<16X} {}{}: 0x{:X}", xStr, index, ctx->registers.regs[index], xStr, index + 1, ctx->registers.regs[index + 1]);
|
||||
}
|
||||
@ -209,11 +209,11 @@ namespace skyline {
|
||||
}
|
||||
|
||||
std::vector<u32> NCE::PatchCode(std::vector<u8> &code, u64 baseAddress, i64 offset) {
|
||||
constexpr auto TpidrroEl0 = 0x5E83; // ID of TPIDRRO_EL0 in MRS
|
||||
constexpr auto CntfrqEl0 = 0x5F00; // ID of CNTFRQ_EL0 in MRS
|
||||
constexpr auto CntpctEl0 = 0x5F01; // ID of CNTPCT_EL0 in MRS
|
||||
constexpr auto CntvctEl0 = 0x5F02; // ID of CNTVCT_EL0 in MRS
|
||||
constexpr auto TegraX1Freq = 19200000; // The clock frequency of the Tegra X1 (19.2 MHz)
|
||||
constexpr u32 TpidrroEl0 = 0x5E83; // ID of TPIDRRO_EL0 in MRS
|
||||
constexpr u32 CntfrqEl0 = 0x5F00; // ID of CNTFRQ_EL0 in MRS
|
||||
constexpr u32 CntpctEl0 = 0x5F01; // ID of CNTPCT_EL0 in MRS
|
||||
constexpr u32 CntvctEl0 = 0x5F02; // ID of CNTVCT_EL0 in MRS
|
||||
constexpr u32 TegraX1Freq = 19200000; // The clock frequency of the Tegra X1 (19.2 MHz)
|
||||
|
||||
u32 *start = reinterpret_cast<u32 *>(code.data());
|
||||
u32 *end = start + (code.size() / sizeof(u32));
|
||||
@ -239,23 +239,30 @@ namespace skyline {
|
||||
auto instrMrs = reinterpret_cast<instr::Mrs *>(address);
|
||||
|
||||
if (instrSvc->Verify()) {
|
||||
// If this is an SVC we need to branch to saveCtx then to the SVC Handler after putting the PC + SVC into X0 and W1 and finally loadCtx before returning to where we were before
|
||||
instr::B bJunc(offset);
|
||||
|
||||
constexpr u32 strLr = 0xF81F0FFE; // STR LR, [SP, #-16]!
|
||||
offset += sizeof(strLr);
|
||||
|
||||
instr::BL bSvCtx(patchOffset - offset);
|
||||
offset += sizeof(bSvCtx);
|
||||
|
||||
auto movPc = instr::MoveU64Reg(regs::X0, baseAddress + (address - start));
|
||||
auto movPc = instr::MoveRegister<u64>(regs::X0, baseAddress + (address - start));
|
||||
offset += sizeof(u32) * movPc.size();
|
||||
|
||||
instr::Movz movCmd(regs::W1, static_cast<u16>(instrSvc->value));
|
||||
offset += sizeof(movCmd);
|
||||
|
||||
instr::BL bSvcHandler((patchOffset + guest::SaveCtxSize + guest::LoadCtxSize) - offset);
|
||||
offset += sizeof(bSvcHandler);
|
||||
|
||||
instr::BL bLdCtx((patchOffset + guest::SaveCtxSize) - offset);
|
||||
offset += sizeof(bLdCtx);
|
||||
|
||||
constexpr u32 ldrLr = 0xF84107FE; // LDR LR, [SP], #16
|
||||
offset += sizeof(ldrLr);
|
||||
|
||||
instr::B bret(-offset + sizeof(u32));
|
||||
offset += sizeof(bret);
|
||||
|
||||
@ -271,24 +278,31 @@ namespace skyline {
|
||||
patch.push_back(bret.raw);
|
||||
} else if (instrMrs->Verify()) {
|
||||
if (instrMrs->srcReg == TpidrroEl0) {
|
||||
// If this moves TPIDRRO_EL0 into a register then we retrieve the value of our virtual TPIDRRO_EL0 from TLS and write it to the register
|
||||
instr::B bJunc(offset);
|
||||
|
||||
u32 strX0{};
|
||||
if (instrMrs->destReg != regs::X0) {
|
||||
strX0 = 0xF81F0FE0; // STR X0, [SP, #-16]!
|
||||
offset += sizeof(strX0);
|
||||
}
|
||||
const u32 mrsX0 = 0xD53BD040; // MRS X0, TPIDR_EL0
|
||||
|
||||
constexpr u32 mrsX0 = 0xD53BD040; // MRS X0, TPIDR_EL0
|
||||
offset += sizeof(mrsX0);
|
||||
const u32 ldrTls = 0xF9408000; // LDR X0, [X0, #256]
|
||||
|
||||
constexpr u32 ldrTls = 0xF9408000; // LDR X0, [X0, #256] (ThreadContext::tpidrroEl0)
|
||||
offset += sizeof(ldrTls);
|
||||
|
||||
u32 movXn{};
|
||||
u32 ldrX0{};
|
||||
if (instrMrs->destReg != regs::X0) {
|
||||
movXn = instr::Mov(regs::X(instrMrs->destReg), regs::X0).raw;
|
||||
offset += sizeof(movXn);
|
||||
|
||||
ldrX0 = 0xF84107E0; // LDR X0, [SP], #16
|
||||
offset += sizeof(ldrX0);
|
||||
}
|
||||
|
||||
instr::B bret(-offset + sizeof(u32));
|
||||
offset += sizeof(bret);
|
||||
|
||||
@ -303,14 +317,19 @@ namespace skyline {
|
||||
patch.push_back(ldrX0);
|
||||
patch.push_back(bret.raw);
|
||||
} else if (frequency != TegraX1Freq) {
|
||||
// These deal with changing the timer registers, we only do this if the clock frequency doesn't match the X1's clock frequency
|
||||
if (instrMrs->srcReg == CntpctEl0) {
|
||||
// If this moves CNTPCT_EL0 into a register then call RescaleClock to rescale the device's clock to the X1's clock frequency and write result to register
|
||||
instr::B bJunc(offset);
|
||||
offset += guest::RescaleClockSize;
|
||||
|
||||
instr::Ldr ldr(0xF94003E0); // LDR XOUT, [SP]
|
||||
ldr.destReg = instrMrs->destReg;
|
||||
offset += sizeof(ldr);
|
||||
const u32 addSp = 0x910083FF; // ADD SP, SP, #32
|
||||
|
||||
constexpr u32 addSp = 0x910083FF; // ADD SP, SP, #32
|
||||
offset += sizeof(addSp);
|
||||
|
||||
instr::B bret(-offset + sizeof(u32));
|
||||
offset += sizeof(bret);
|
||||
|
||||
@ -322,9 +341,12 @@ namespace skyline {
|
||||
patch.push_back(addSp);
|
||||
patch.push_back(bret.raw);
|
||||
} else if (instrMrs->srcReg == CntfrqEl0) {
|
||||
// If this moves CNTFRQ_EL0 into a register then move the Tegra X1's clock frequency into the register (Rather than the host clock frequency)
|
||||
instr::B bJunc(offset);
|
||||
auto movFreq = instr::MoveU32Reg(static_cast<regs::X>(instrMrs->destReg), TegraX1Freq);
|
||||
|
||||
auto movFreq = instr::MoveRegister<u32>(static_cast<regs::X>(instrMrs->destReg), TegraX1Freq);
|
||||
offset += sizeof(u32) * movFreq.size();
|
||||
|
||||
instr::B bret(-offset + sizeof(u32));
|
||||
offset += sizeof(bret);
|
||||
|
||||
@ -334,9 +356,10 @@ namespace skyline {
|
||||
patch.push_back(bret.raw);
|
||||
}
|
||||
} else {
|
||||
// If the host clock frequency is the same as the Tegra X1's clock frequency
|
||||
if (instrMrs->srcReg == CntpctEl0) {
|
||||
instr::Mrs mrs(CntvctEl0, regs::X(instrMrs->destReg));
|
||||
*address = mrs.raw;
|
||||
// If this moves CNTPCT_EL0 into a register, change the instruction to move CNTVCT_EL0 instead as Linux or most other OSes don't allow access to CNTPCT_EL0 rather only CNTVCT_EL0 can be accessed from userspace
|
||||
*address = instr::Mrs(CntvctEl0, regs::X(instrMrs->destReg)).raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <cstdlib>
|
||||
#include <initializer_list> // This is used implicitly
|
||||
#include <asm/siginfo.h>
|
||||
#include <unistd.h>
|
||||
#include <asm/unistd.h>
|
||||
#include "guest_common.h"
|
||||
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline // NOLINT(cppcoreguidelines-macro-usage)
|
||||
@ -98,54 +100,14 @@ namespace skyline::guest {
|
||||
/**
|
||||
* @note Do not use any functions that cannot be inlined from this, as this function is placed at an arbitrary address in the guest. In addition, do not use any static variables or globals as the .bss section is not copied into the guest.
|
||||
*/
|
||||
void SvcHandler(u64 pc, u32 svc) {
|
||||
void SvcHandler(u64 pc, u16 svc) {
|
||||
volatile ThreadContext *ctx;
|
||||
asm("MRS %0, TPIDR_EL0":"=r"(ctx));
|
||||
|
||||
ctx->pc = pc;
|
||||
ctx->commandId = svc;
|
||||
ctx->svc = svc;
|
||||
|
||||
if (svc == 0xB) { // svcSleepThread
|
||||
switch (ctx->registers.x0) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2: {
|
||||
asm("MOV X0, XZR\n\t"
|
||||
"MOV X1, XZR\n\t"
|
||||
"MOV X2, XZR\n\t"
|
||||
"MOV X3, XZR\n\t"
|
||||
"MOV X4, XZR\n\t"
|
||||
"MOV X5, XZR\n\t"
|
||||
"MOV X8, #124\n\t" // __NR_sched_yield
|
||||
"STR LR, [SP, #-16]!\n\t"
|
||||
"MOV LR, SP\n\t"
|
||||
"SVC #0\n\t"
|
||||
"MOV SP, LR\n\t"
|
||||
"LDR LR, [SP], #16":: : "x0", "x1", "x2", "x3", "x4", "x5", "x8");
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
struct timespec spec = {
|
||||
.tv_sec = static_cast<time_t>(ctx->registers.x0 / 1000000000),
|
||||
.tv_nsec = static_cast<long>(ctx->registers.x0 % 1000000000)
|
||||
};
|
||||
asm("MOV X0, %0\n\t"
|
||||
"MOV X1, XZR\n\t"
|
||||
"MOV X2, XZR\n\t"
|
||||
"MOV X3, XZR\n\t"
|
||||
"MOV X4, XZR\n\t"
|
||||
"MOV X5, XZR\n\t"
|
||||
"MOV X8, #101\n\t" // __NR_nanosleep
|
||||
"STR LR, [SP, #-16]!\n\t"
|
||||
"MOV LR, SP\n\t"
|
||||
"SVC #0\n\t"
|
||||
"MOV SP, LR\n\t"
|
||||
"LDR LR, [SP], #16"::"r"(&spec) : "x0", "x1", "x2", "x3", "x4", "x5", "x8");
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (svc == 0x1E) { // svcGetSystemTick
|
||||
if (svc == 0x1E) { // svcGetSystemTick
|
||||
asm("STP X1, X2, [SP, #-16]!\n\t"
|
||||
"STR Q0, [SP, #-16]!\n\t"
|
||||
"STR Q1, [SP, #-16]!\n\t"
|
||||
@ -175,7 +137,7 @@ namespace skyline::guest {
|
||||
if (ctx->state == ThreadState::WaitRun) {
|
||||
break;
|
||||
} else if (ctx->state == ThreadState::WaitFunc) {
|
||||
if (ctx->commandId == static_cast<u32>(ThreadCall::Syscall)) {
|
||||
if (ctx->threadCall == ThreadCall::Syscall) {
|
||||
SaveCtxStack();
|
||||
LoadCtxTls();
|
||||
|
||||
@ -187,7 +149,7 @@ namespace skyline::guest {
|
||||
|
||||
SaveCtxTls();
|
||||
LoadCtxStack();
|
||||
} else if (ctx->commandId == static_cast<u32>(ThreadCall::Memcopy)) {
|
||||
} else if (ctx->threadCall == ThreadCall::Memcopy) {
|
||||
auto src = reinterpret_cast<u8 *>(ctx->registers.x0);
|
||||
auto dest = reinterpret_cast<u8 *>(ctx->registers.x1);
|
||||
auto size = ctx->registers.x2;
|
||||
@ -195,7 +157,7 @@ namespace skyline::guest {
|
||||
|
||||
while (src < end)
|
||||
*(src++) = *(dest++);
|
||||
} else if (ctx->commandId == static_cast<u32>(ThreadCall::Clone)) {
|
||||
} else if (ctx->threadCall == ThreadCall::Clone) {
|
||||
SaveCtxStack();
|
||||
LoadCtxTls();
|
||||
|
||||
@ -248,7 +210,15 @@ namespace skyline::guest {
|
||||
ctx->state = ThreadState::Running;
|
||||
}
|
||||
|
||||
void SignalHandler(int signal, siginfo_t *info, ucontext_t *ucontext) {
|
||||
[[noreturn]] void Exit(int) {
|
||||
if (gettid() == getpid())
|
||||
syscall(__NR_exit_group, 0);
|
||||
else
|
||||
syscall(__NR_exit, 0);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
[[noreturn]] void SignalHandler(int signal, siginfo_t *info, ucontext_t *ucontext) {
|
||||
volatile ThreadContext *ctx;
|
||||
asm("MRS %0, TPIDR_EL0":"=r"(ctx));
|
||||
|
||||
@ -256,7 +226,7 @@ namespace skyline::guest {
|
||||
ctx->registers.regs[index] = ucontext->uc_mcontext.regs[index];
|
||||
|
||||
ctx->pc = ucontext->uc_mcontext.pc;
|
||||
ctx->commandId = static_cast<u32>(signal);
|
||||
ctx->signal = static_cast<u32>(signal);
|
||||
ctx->faultAddress = ucontext->uc_mcontext.fault_address;
|
||||
ctx->sp = ucontext->uc_mcontext.sp;
|
||||
|
||||
@ -264,7 +234,7 @@ namespace skyline::guest {
|
||||
ctx->state = ThreadState::GuestCrash;
|
||||
|
||||
if (ctx->state == ThreadState::WaitRun)
|
||||
exit(0);
|
||||
Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -279,7 +249,7 @@ namespace skyline::guest {
|
||||
if (ctx->state == ThreadState::WaitRun) {
|
||||
break;
|
||||
} else if (ctx->state == ThreadState::WaitFunc) {
|
||||
if (ctx->commandId == static_cast<u32>(ThreadCall::Syscall)) {
|
||||
if (ctx->threadCall == ThreadCall::Syscall) {
|
||||
SaveCtxStack();
|
||||
LoadCtxTls();
|
||||
|
||||
@ -292,7 +262,7 @@ namespace skyline::guest {
|
||||
SaveCtxTls();
|
||||
LoadCtxStack();
|
||||
}
|
||||
} else if (ctx->commandId == static_cast<u32>(ThreadCall::Memcopy)) {
|
||||
} else if (ctx->threadCall == ThreadCall::Memcopy) {
|
||||
auto src = reinterpret_cast<u8 *>(ctx->registers.x0);
|
||||
auto dest = reinterpret_cast<u8 *>(ctx->registers.x1);
|
||||
auto size = ctx->registers.x2;
|
||||
@ -311,6 +281,12 @@ namespace skyline::guest {
|
||||
for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV})
|
||||
sigaction(signal, &sigact, nullptr);
|
||||
|
||||
sigact = {
|
||||
.sa_handler = Exit,
|
||||
};
|
||||
|
||||
sigaction(SIGTERM, &sigact, nullptr);
|
||||
|
||||
ctx->state = ThreadState::Running;
|
||||
|
||||
asm("MOV LR, %0\n\t"
|
||||
|
@ -42,6 +42,6 @@ namespace skyline {
|
||||
* @param pc The address of PC when the call was being done
|
||||
* @param svc The SVC ID of the SVC being called
|
||||
*/
|
||||
void SvcHandler(u64 pc, u32 svc);
|
||||
void SvcHandler(u64 pc, u16 svc);
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ namespace skyline {
|
||||
/**
|
||||
* @brief This enumeration is used to convey the state of a thread to the kernel
|
||||
*/
|
||||
enum class ThreadState : u32 {
|
||||
enum class ThreadState : u8 {
|
||||
NotReady = 0, //!< The thread hasn't yet entered the entry handler
|
||||
Running = 1, //!< The thread is currently executing code
|
||||
WaitKernel = 2, //!< The thread is currently waiting on the kernel
|
||||
@ -136,10 +136,10 @@ namespace skyline {
|
||||
/**
|
||||
* @brief This enumeration holds the functions that can be run on the guest process
|
||||
*/
|
||||
enum class ThreadCall : u32 {
|
||||
Syscall = 0x100, //!< A linux syscall needs to be called from the guest
|
||||
Memcopy = 0x101, //!< To copy memory from one location to another
|
||||
Clone = 0x102, //!< Use the clone syscall to create a new thread
|
||||
enum class ThreadCall : u8 {
|
||||
Syscall = 1, //!< A linux syscall needs to be called from the guest
|
||||
Memcopy = 2, //!< To copy memory from one location to another
|
||||
Clone = 3, //!< Use the clone syscall to create a new thread
|
||||
};
|
||||
|
||||
/**
|
||||
@ -147,7 +147,9 @@ namespace skyline {
|
||||
*/
|
||||
struct ThreadContext {
|
||||
ThreadState state; //!< The state of the guest
|
||||
u32 commandId; //!< The command ID of the current kernel call/function call
|
||||
ThreadCall threadCall; //!< The function to run in the guest process
|
||||
u16 svc; //!< The SVC ID of the current kernel call
|
||||
u32 signal; //!< The signal caught by the guest process
|
||||
u64 pc; //!< The program counter register on the guest
|
||||
Registers registers; //!< The general purpose registers on the guest
|
||||
u64 tpidrroEl0; //!< The value for TPIDRRO_EL0 for the current thread
|
||||
|
@ -190,12 +190,12 @@ namespace skyline {
|
||||
* @brief Creates a MOVZ instruction
|
||||
* @param destReg The destination Xn register to store the value in
|
||||
* @param imm16 The 16-bit value to store
|
||||
* @param shift The offset (in bits and 16-bit aligned) in the register to store the value at
|
||||
* @param shift The offset (in units of 16-bits) in the register to store the value at
|
||||
*/
|
||||
inline constexpr Movz(regs::X destReg, u16 imm16, u8 shift = 0) {
|
||||
this->destReg = static_cast<u8>(destReg);
|
||||
this->imm16 = imm16;
|
||||
hw = static_cast<u8>(shift / 16);
|
||||
hw = shift;
|
||||
sig = 0xA5;
|
||||
sf = 1;
|
||||
}
|
||||
@ -204,22 +204,22 @@ namespace skyline {
|
||||
* @brief Creates a MOVZ instruction
|
||||
* @param destReg The destination Wn register to store the value in
|
||||
* @param imm16 The 16-bit value to store
|
||||
* @param shift The offset (in bits and 16-bit aligned) in the register to store the value at
|
||||
* @param shift The offset (in units of 16-bits) in the register to store the value at
|
||||
*/
|
||||
inline constexpr Movz(regs::W destReg, u16 imm16, u8 shift = 0) {
|
||||
this->destReg = static_cast<u8>(destReg);
|
||||
this->imm16 = imm16;
|
||||
hw = static_cast<u8>(shift / 16);
|
||||
hw = shift;
|
||||
sig = 0xA5;
|
||||
sf = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the offset of the instruction
|
||||
* @return The offset encoded within the instruction
|
||||
* @return The offset encoded within the instruction (In Bytes)
|
||||
*/
|
||||
inline constexpr u8 Shift() {
|
||||
return static_cast<u8>(hw * 16);
|
||||
return static_cast<u8>(hw * sizeof(u16));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,12 +252,12 @@ namespace skyline {
|
||||
* @brief Creates a MOVK instruction
|
||||
* @param destReg The destination Xn register to store the value in
|
||||
* @param imm16 The 16-bit value to store
|
||||
* @param shift The offset (in bits and 16-bit aligned) in the register to store the value at
|
||||
* @param shift The offset (in units of 16-bits) in the register to store the value at
|
||||
*/
|
||||
inline constexpr Movk(regs::X destReg, u16 imm16, u8 shift = 0) {
|
||||
this->destReg = static_cast<u8>(destReg);
|
||||
this->imm16 = imm16;
|
||||
hw = static_cast<u8>(shift / 16);
|
||||
hw = shift;
|
||||
sig = 0xE5;
|
||||
sf = 1;
|
||||
}
|
||||
@ -266,22 +266,22 @@ namespace skyline {
|
||||
* @brief Creates a MOVK instruction
|
||||
* @param destReg The destination Wn register to store the value in
|
||||
* @param imm16 The 16-bit value to store
|
||||
* @param shift The offset (in bits and 16-bit aligned) in the register to store the value at
|
||||
* @param shift The offset (in units of 16-bits) in the register to store the value at
|
||||
*/
|
||||
inline constexpr Movk(regs::W destReg, u16 imm16, u8 shift = 0) {
|
||||
this->destReg = static_cast<u8>(destReg);
|
||||
this->imm16 = imm16;
|
||||
hw = static_cast<u8>(shift / 16);
|
||||
hw = shift;
|
||||
sig = 0xE5;
|
||||
sf = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the offset of the instruction
|
||||
* @return The offset encoded within the instruction
|
||||
* @return The offset encoded within the instruction (In Bytes)
|
||||
*/
|
||||
inline constexpr u8 Shift() {
|
||||
return static_cast<u8>(hw * 16);
|
||||
return static_cast<u8>(hw * sizeof(u16));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,57 +306,27 @@ namespace skyline {
|
||||
static_assert(sizeof(Movk) == sizeof(u32));
|
||||
|
||||
/**
|
||||
* @param destReg The destination register of the operation
|
||||
* @param value The 64-bit value to insert into the register
|
||||
* @return A vector with the instructions to insert the value
|
||||
* @param destination The destination register of the operation
|
||||
* @param value The value to insert into the register
|
||||
* @return A array with the instructions to insert the value
|
||||
*/
|
||||
inline const std::vector<u32> MoveU64Reg(regs::X destReg, u64 value) {
|
||||
union {
|
||||
u64 val;
|
||||
struct {
|
||||
u16 v0;
|
||||
u16 v16;
|
||||
u16 v32;
|
||||
u16 v48;
|
||||
};
|
||||
} val;
|
||||
val.val = value;
|
||||
std::vector<u32> instr;
|
||||
instr::Movz mov0(destReg, val.v0, 0);
|
||||
instr.push_back(mov0.raw);
|
||||
instr::Movk mov16(destReg, val.v16, 16);
|
||||
if (val.v16)
|
||||
instr.push_back(mov16.raw);
|
||||
instr::Movk mov32(destReg, val.v32, 32);
|
||||
if (val.v32)
|
||||
instr.push_back(mov32.raw);
|
||||
instr::Movk mov48(destReg, val.v48, 48);
|
||||
if (val.v48)
|
||||
instr.push_back(mov48.raw);
|
||||
return instr;
|
||||
template<typename Type>
|
||||
inline constexpr std::array<u32, sizeof(Type) / sizeof(u16)> MoveRegister(regs::X destination, Type value) {
|
||||
std::array<u32, sizeof(Type) / sizeof(u16)> instructions;
|
||||
|
||||
auto valuePointer = reinterpret_cast<u16 *>(&value);
|
||||
u8 offset{};
|
||||
|
||||
for (auto &instruction : instructions) {
|
||||
if (offset)
|
||||
instruction = instr::Movk(destination, *(valuePointer + offset), offset).raw;
|
||||
else
|
||||
instruction = instr::Movz(destination, *(valuePointer + offset), offset).raw;
|
||||
|
||||
offset++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param destReg The destination register of the operation
|
||||
* @param value The 32-bit value to insert into the register
|
||||
* @return A vector with the instructions to insert the value
|
||||
*/
|
||||
inline const std::vector<u32> MoveU32Reg(regs::X destReg, u32 value) {
|
||||
union {
|
||||
u32 val;
|
||||
struct {
|
||||
u16 v0;
|
||||
u16 v16;
|
||||
};
|
||||
} val;
|
||||
val.val = value;
|
||||
std::vector<u32> instr;
|
||||
instr::Movz mov0(destReg, val.v0, 0);
|
||||
instr.push_back(mov0.raw);
|
||||
instr::Movk mov16(destReg, val.v16, 16);
|
||||
if (val.v16)
|
||||
instr.push_back(mov16.raw);
|
||||
return instr;
|
||||
return instructions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,7 @@
|
||||
namespace skyline::kernel {
|
||||
OS::OS(std::shared_ptr<JvmManager> &jvmManager, std::shared_ptr<Logger> &logger, std::shared_ptr<Settings> &settings) : state(this, process, jvmManager, settings, logger), memory(state), serviceManager(state) {}
|
||||
|
||||
void OS::Execute(const int romFd, const TitleFormat romType) {
|
||||
void OS::Execute(int romFd, TitleFormat romType) {
|
||||
std::shared_ptr<loader::Loader> loader;
|
||||
|
||||
if (romType == TitleFormat::NRO) {
|
||||
@ -33,7 +33,7 @@ namespace skyline::kernel {
|
||||
auto tlsMem = std::make_shared<type::KSharedMemory>(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission{true, true, false}, memory::states::Reserved);
|
||||
tlsMem->guest = tlsMem->kernel;
|
||||
|
||||
pid_t pid = clone(reinterpret_cast<int (*)(void *)>(&guest::GuestEntry), reinterpret_cast<void *>(stack->guest.address + stackSize), CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast<void *>(entry), nullptr, reinterpret_cast<void *>(tlsMem->guest.address));
|
||||
auto pid = clone(reinterpret_cast<int (*)(void *)>(&guest::GuestEntry), reinterpret_cast<void *>(stack->guest.address + stackSize), CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast<void *>(entry), nullptr, reinterpret_cast<void *>(tlsMem->guest.address));
|
||||
if (pid == -1)
|
||||
throw exception("Call to clone() has failed: {}", strerror(errno));
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace skyline::kernel {
|
||||
* @param romFd A FD to the ROM file to execute
|
||||
* @param romType The type of the ROM file
|
||||
*/
|
||||
void Execute(const int romFd, const TitleFormat romType);
|
||||
void Execute(int romFd, TitleFormat romType);
|
||||
|
||||
/**
|
||||
* @brief Creates a new process
|
||||
|
@ -34,6 +34,7 @@ namespace skyline::service::am {
|
||||
response.errorCode = constant::status::NoMessages;
|
||||
return;
|
||||
}
|
||||
|
||||
response.Push(messageQueue.front());
|
||||
messageQueue.pop();
|
||||
}
|
||||
|
@ -25,10 +25,12 @@ namespace skyline::service::am {
|
||||
|
||||
void ISelfController::CreateManagedDisplayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
state.logger->Debug("Creating Managed Layer on Default Display");
|
||||
|
||||
auto hosBinder = state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>(Service::hosbinder_IHOSBinderDriver);
|
||||
if (hosBinder->layerStatus != hosbinder::LayerStatus::Uninitialized)
|
||||
throw exception("The application is creating more than one layer");
|
||||
hosBinder->layerStatus = hosbinder::LayerStatus::Managed;
|
||||
|
||||
response.Push<u64>(0);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "IAudioOut.h"
|
||||
|
||||
namespace skyline::service::audio {
|
||||
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, const u8 channelCount, const u32 sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, Service::audio_IAudioOut, "audio:IAudioOut", {
|
||||
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, u8 channelCount, u32 sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, Service::audio_IAudioOut, "audio:IAudioOut", {
|
||||
{0x0, SFUNC(IAudioOut::GetAudioOutState)},
|
||||
{0x1, SFUNC(IAudioOut::StartAudioOut)},
|
||||
{0x2, SFUNC(IAudioOut::StopAudioOut)},
|
||||
|
@ -28,7 +28,7 @@ namespace skyline::service::audio {
|
||||
* @param channelCount The channel count of the audio data the audio out will be fed
|
||||
* @param sampleRate The sample rate of the audio data the audio out will be fed
|
||||
*/
|
||||
IAudioOut(const DeviceState &state, ServiceManager &manager, const u8 channelCount, const u32 sampleRate);
|
||||
IAudioOut(const DeviceState &state, ServiceManager &manager, u8 channelCount, u32 sampleRate);
|
||||
|
||||
/**
|
||||
* @brief Closes the audio track
|
||||
|
@ -91,12 +91,12 @@ namespace skyline::service {
|
||||
class BaseService {
|
||||
protected:
|
||||
const DeviceState &state; //!< The state of the device
|
||||
ServiceManager &manager; //!< A pointer to the service manager
|
||||
const std::unordered_map<u32, std::function<void(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>> vTable; //!< This holds the mapping from an object's CmdId to the actual function
|
||||
ServiceManager &manager; //!< A reference to the service manager
|
||||
std::unordered_map<u32, std::function<void(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>> vTable; //!< This holds the mapping from a function's CmdId to the actual function
|
||||
|
||||
public:
|
||||
const Service serviceType; //!< The type of the service this is
|
||||
const std::string serviceName; //!< The name of the service
|
||||
Service serviceType; //!< The type of this service
|
||||
std::string serviceName; //!< The name of this service
|
||||
|
||||
/**
|
||||
* @param state The state of the device
|
||||
@ -105,7 +105,7 @@ namespace skyline::service {
|
||||
* @param serviceName The name of the service
|
||||
* @param vTable The functions of the service
|
||||
*/
|
||||
BaseService(const DeviceState &state, ServiceManager &manager, const Service serviceType, const std::string &serviceName, const std::unordered_map<u32, std::function<void(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>> &vTable) : state(state), manager(manager), serviceType(serviceType), serviceName(serviceName), vTable(vTable) {}
|
||||
BaseService(const DeviceState &state, ServiceManager &manager, Service serviceType, const std::string &serviceName, const std::unordered_map<u32, std::function<void(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>> &vTable) : state(state), manager(manager), serviceType(serviceType), serviceName(serviceName), vTable(vTable) {}
|
||||
|
||||
/**
|
||||
* @brief This handles all IPC commands with type request to a service
|
||||
|
@ -11,6 +11,6 @@ namespace skyline::service::fatalsrv {
|
||||
}) {}
|
||||
|
||||
void IService::ThrowFatal(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
throw exception("A fatal error with code: 0x{:X} has caused emulation to stop", *reinterpret_cast<u32 *>(request.cmdArg));
|
||||
throw exception("A fatal error with code: 0x{:X} has caused emulation to stop", request.Pop<u32>());
|
||||
}
|
||||
}
|
||||
|
@ -4,5 +4,5 @@
|
||||
#include "IFileSystem.h"
|
||||
|
||||
namespace skyline::service::fssrv {
|
||||
IFileSystem::IFileSystem(const FsType type, const DeviceState &state, ServiceManager &manager) : type(type), BaseService(state, manager, Service::fssrv_IFileSystem, "fssrv:IFileSystem", {}) {}
|
||||
IFileSystem::IFileSystem(FsType type, const DeviceState &state, ServiceManager &manager) : type(type), BaseService(state, manager, Service::fssrv_IFileSystem, "fssrv:IFileSystem", {}) {}
|
||||
}
|
||||
|
@ -11,9 +11,9 @@ namespace skyline::service::fssrv {
|
||||
* @brief These are the possible types of the filesystem
|
||||
*/
|
||||
enum class FsType {
|
||||
Nand,
|
||||
SdCard,
|
||||
GameCard
|
||||
Nand, //!< The internal NAND storage
|
||||
SdCard, //!< The external SDCard storage
|
||||
GameCard, //!< The Game-Card of the inserted game (https://switchbrew.org/wiki/Gamecard)
|
||||
};
|
||||
|
||||
/**
|
||||
@ -21,7 +21,7 @@ namespace skyline::service::fssrv {
|
||||
*/
|
||||
class IFileSystem : public BaseService {
|
||||
public:
|
||||
const FsType type;
|
||||
FsType type; //!< The type of filesystem this class represents
|
||||
|
||||
IFileSystem(FsType type, const DeviceState &state, ServiceManager &manager);
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ namespace skyline::service::fssrv {
|
||||
}) {}
|
||||
|
||||
void IFileSystemProxy::SetCurrentProcess(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
process = *reinterpret_cast<pid_t *>(request.cmdArg);
|
||||
process = request.Pop<pid_t>();
|
||||
}
|
||||
|
||||
void IFileSystemProxy::OpenSdCardFileSystem(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
|
@ -12,6 +12,7 @@ namespace skyline::service::hid {
|
||||
hidSharedMemory = std::make_shared<kernel::type::KSharedMemory>(state, NULL, constant::HidSharedMemSize, memory::Permission{true, false, false});
|
||||
auto handle = state.process->InsertItem<type::KSharedMemory>(hidSharedMemory);
|
||||
state.logger->Debug("HID Shared Memory Handle: 0x{:X}", handle);
|
||||
|
||||
response.copyHandles.push_back(handle);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ namespace skyline::service::hid {
|
||||
const auto &buffer = request.inputBuf.at(0);
|
||||
size_t numId = buffer.size / sizeof(NpadId);
|
||||
u64 address = buffer.address;
|
||||
|
||||
for (size_t i = 0; i < numId; i++) {
|
||||
auto id = state.process->GetObject<NpadId>(address);
|
||||
deviceMap[id] = JoyConDevice(id);
|
||||
@ -50,6 +51,7 @@ namespace skyline::service::hid {
|
||||
void IHidServer::SetNpadJoyAssignmentModeSingle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto controllerId = request.Pop<NpadId>();
|
||||
auto appletUserId = request.Pop<u64>();
|
||||
|
||||
deviceMap[controllerId].assignment = JoyConAssignment::Single;
|
||||
deviceMap[controllerId].side = request.Pop<JoyConSide>();
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <os.h>
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include <services/nvdrv/INvDrvServices.h>
|
||||
#include <gpu/format.h>
|
||||
#include "IHOSBinderDriver.h"
|
||||
#include "display.h"
|
||||
|
||||
@ -123,9 +124,9 @@ namespace skyline::service::hosbinder {
|
||||
std::shared_ptr<nvdrv::device::NvMap::NvMapObject> nvBuffer{};
|
||||
auto nvmap = state.os->serviceManager.GetService<nvdrv::INvDrvServices>(Service::nvdrv_INvDrvServices)->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap);
|
||||
|
||||
if (gbpBuffer->nvmapHandle)
|
||||
if (gbpBuffer->nvmapHandle) {
|
||||
nvBuffer = nvmap->handleTable.at(gbpBuffer->nvmapHandle);
|
||||
else {
|
||||
} else {
|
||||
for (const auto &object : nvmap->handleTable) {
|
||||
if (object.second->id == gbpBuffer->nvmapId) {
|
||||
nvBuffer = object.second;
|
||||
@ -140,10 +141,10 @@ namespace skyline::service::hosbinder {
|
||||
switch (gbpBuffer->format) {
|
||||
case WINDOW_FORMAT_RGBA_8888:
|
||||
case WINDOW_FORMAT_RGBX_8888:
|
||||
format = gpu::texture::format::RGBA8888Unorm;
|
||||
format = gpu::format::RGBA8888Unorm;
|
||||
break;
|
||||
case WINDOW_FORMAT_RGB_565:
|
||||
format = gpu::texture::format::RGB565Unorm;
|
||||
format = gpu::format::RGB565Unorm;
|
||||
break;
|
||||
default:
|
||||
throw exception("Unknown pixel format used for FB");
|
||||
|
@ -22,28 +22,35 @@ namespace skyline::service::nvdrv {
|
||||
|
||||
std::shared_ptr<device::NvDevice> object;
|
||||
switch (type) {
|
||||
case (device::NvDeviceType::nvhost_ctrl):
|
||||
case device::NvDeviceType::nvhost_ctrl:
|
||||
object = std::make_shared<device::NvHostCtrl>(state);
|
||||
break;
|
||||
case (device::NvDeviceType::nvhost_gpu):
|
||||
case (device::NvDeviceType::nvhost_vic):
|
||||
case (device::NvDeviceType::nvhost_nvdec):
|
||||
|
||||
case device::NvDeviceType::nvhost_gpu:
|
||||
case device::NvDeviceType::nvhost_vic:
|
||||
case device::NvDeviceType::nvhost_nvdec:
|
||||
object = std::make_shared<device::NvHostChannel>(state, type);
|
||||
break;
|
||||
case (device::NvDeviceType::nvhost_ctrl_gpu):
|
||||
|
||||
case device::NvDeviceType::nvhost_ctrl_gpu:
|
||||
object = std::make_shared<device::NvHostCtrlGpu>(state);
|
||||
break;
|
||||
case (device::NvDeviceType::nvmap):
|
||||
|
||||
case device::NvDeviceType::nvmap:
|
||||
object = std::make_shared<device::NvMap>(state);
|
||||
break;
|
||||
case (device::NvDeviceType::nvhost_as_gpu):
|
||||
|
||||
case device::NvDeviceType::nvhost_as_gpu:
|
||||
object = std::make_shared<device::NvHostAsGpu>(state);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw exception("Cannot find NVDRV device");
|
||||
}
|
||||
|
||||
deviceMap[type] = object;
|
||||
fdMap[fdIndex] = object;
|
||||
|
||||
return fdIndex++;
|
||||
}
|
||||
|
||||
@ -59,6 +66,7 @@ namespace skyline::service::nvdrv {
|
||||
void INvDrvServices::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto buffer = request.inputBuf.at(0);
|
||||
auto path = state.process->GetString(buffer.address, buffer.size);
|
||||
|
||||
response.Push<u32>(OpenDevice(path));
|
||||
response.Push<u32>(constant::status::Success);
|
||||
}
|
||||
@ -66,20 +74,24 @@ namespace skyline::service::nvdrv {
|
||||
void INvDrvServices::Ioctl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto fd = request.Pop<u32>();
|
||||
auto cmd = request.Pop<u32>();
|
||||
|
||||
state.logger->Debug("IOCTL on device: 0x{:X}, cmd: 0x{:X}", fd, cmd);
|
||||
try {
|
||||
if (request.inputBuf.empty() || request.outputBuf.empty()) {
|
||||
if (request.inputBuf.empty()) {
|
||||
device::IoctlData data(request.outputBuf.at(0));
|
||||
|
||||
fdMap.at(fd)->HandleIoctl(cmd, data);
|
||||
response.Push<u32>(data.status);
|
||||
} else {
|
||||
device::IoctlData data(request.inputBuf.at(0));
|
||||
|
||||
fdMap.at(fd)->HandleIoctl(cmd, data);
|
||||
response.Push<u32>(data.status);
|
||||
}
|
||||
} else {
|
||||
device::IoctlData data(request.inputBuf.at(0), request.outputBuf.at(0));
|
||||
|
||||
fdMap.at(fd)->HandleIoctl(cmd, data);
|
||||
response.Push<u32>(data.status);
|
||||
}
|
||||
@ -89,16 +101,19 @@ namespace skyline::service::nvdrv {
|
||||
}
|
||||
|
||||
void INvDrvServices::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
u32 fd = *reinterpret_cast<u32 *>(request.cmdArg);
|
||||
auto fd = request.Pop<u32>();
|
||||
state.logger->Debug("Closing NVDRV device ({})", fd);
|
||||
|
||||
try {
|
||||
auto device = fdMap.at(fd);
|
||||
if (!--device->refCount)
|
||||
deviceMap.erase(device->deviceType);
|
||||
|
||||
fdMap.erase(fd);
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("Trying to close non-existent FD");
|
||||
}
|
||||
|
||||
response.Push<u32>(constant::status::Success);
|
||||
}
|
||||
|
||||
@ -111,6 +126,7 @@ namespace skyline::service::nvdrv {
|
||||
auto eventId = request.Pop<u32>();
|
||||
auto event = std::make_shared<type::KEvent>(state);
|
||||
auto handle = state.process->InsertItem<type::KEvent>(event);
|
||||
|
||||
state.logger->Debug("QueryEvent: FD: {}, Event ID: {}, Handle: {}", fd, eventId, handle);
|
||||
response.copyHandles.push_back(handle);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace skyline::service::nvdrv::device {
|
||||
|
||||
void NvHostChannel::SetPriority(IoctlData &buffer) {
|
||||
auto priority = state.process->GetObject<NvChannelPriority>(buffer.input[0].address);
|
||||
|
||||
switch (priority) {
|
||||
case NvChannelPriority::Low:
|
||||
timeslice = 1300;
|
||||
|
@ -31,6 +31,7 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 subregionHeightAlignPixels{0x40};
|
||||
u32 subregionCount{0x10};
|
||||
} zCullInfo;
|
||||
|
||||
state.process->WriteMemory(zCullInfo, buffer.output[0].address);
|
||||
}
|
||||
|
||||
@ -72,11 +73,13 @@ namespace skyline::service::nvdrv::device {
|
||||
u64 chipName; // 0x6230326D67 ("gm20b")
|
||||
u64 grCompbitStoreBaseHw; // 0x0 (not supported)
|
||||
};
|
||||
|
||||
struct Data {
|
||||
u64 gpuCharacteristicsBufSize; // InOut
|
||||
u64 gpuCharacteristicsBufAddr; // In
|
||||
GpuCharacteristics gpuCharacteristics; // Out
|
||||
} data = state.process->GetObject<Data>(buffer.input[0].address);
|
||||
|
||||
data.gpuCharacteristics = {
|
||||
.arch = 0x120,
|
||||
.impl = 0xB,
|
||||
@ -113,7 +116,9 @@ namespace skyline::service::nvdrv::device {
|
||||
.chipName = 0x6230326D67,
|
||||
.grCompbitStoreBaseHw = 0x0
|
||||
};
|
||||
|
||||
data.gpuCharacteristicsBufSize = 0xA0;
|
||||
|
||||
state.process->WriteMemory(data, buffer.output[0].address);
|
||||
}
|
||||
|
||||
@ -123,8 +128,10 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 reserved[3]; // In
|
||||
u64 maskBuf; // Out
|
||||
} data = state.process->GetObject<Data>(buffer.input[0].address);
|
||||
|
||||
if (data.maskBufSize)
|
||||
data.maskBuf = 0x3;
|
||||
|
||||
state.process->WriteMemory(data, buffer.output[0].address);
|
||||
}
|
||||
|
||||
@ -136,6 +143,7 @@ namespace skyline::service::nvdrv::device {
|
||||
.slot = 0x07,
|
||||
.mask = 0x01
|
||||
};
|
||||
|
||||
state.process->WriteMemory(data, buffer.output[0].address);
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,10 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 size; // In
|
||||
u32 handle; // Out
|
||||
} data = state.process->GetObject<Data>(buffer.input[0].address);
|
||||
|
||||
handleTable[handleIndex] = std::make_shared<NvMapObject>(idIndex++, data.size);
|
||||
data.handle = handleIndex++;
|
||||
|
||||
state.process->WriteMemory(data, buffer.output[0].address);
|
||||
state.logger->Debug("Create: Input: Size: 0x{:X}, Output: Handle: 0x{:X}, Status: {}", data.size, data.handle, buffer.status);
|
||||
}
|
||||
@ -32,6 +34,7 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 id; // In
|
||||
u32 handle; // Out
|
||||
} data = state.process->GetObject<Data>(buffer.input[0].address);
|
||||
|
||||
bool found{};
|
||||
for (const auto &object : handleTable) {
|
||||
if (object.second->id == data.id) {
|
||||
@ -40,10 +43,12 @@ namespace skyline::service::nvdrv::device {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
state.process->WriteMemory(data, buffer.output[0].address);
|
||||
else
|
||||
buffer.status = NvStatus::BadValue;
|
||||
|
||||
state.logger->Debug("FromId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status);
|
||||
}
|
||||
|
||||
@ -57,6 +62,7 @@ namespace skyline::service::nvdrv::device {
|
||||
u8 _pad0_[7];
|
||||
u64 address; // InOut
|
||||
} data = state.process->GetObject<Data>(buffer.input[0].address);
|
||||
|
||||
auto &object = handleTable.at(data.handle);
|
||||
object->heapMask = data.heapMask;
|
||||
object->flags = data.flags;
|
||||
@ -64,6 +70,7 @@ namespace skyline::service::nvdrv::device {
|
||||
object->kind = data.kind;
|
||||
object->address = data.address;
|
||||
object->status = NvMapObject::Status::Allocated;
|
||||
|
||||
state.logger->Debug("Alloc: Input: Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}, Output: Status: {}", data.handle, data.heapMask, data.flags, data.align, data.kind, data.address, buffer.status);
|
||||
}
|
||||
|
||||
@ -75,6 +82,7 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 size; // Out
|
||||
u64 flags; // Out
|
||||
} data = state.process->GetObject<Data>(buffer.input[0].address);
|
||||
|
||||
const auto &object = handleTable.at(data.handle);
|
||||
if (object.use_count() > 1) {
|
||||
data.address = static_cast<u32>(object->address);
|
||||
@ -83,8 +91,10 @@ namespace skyline::service::nvdrv::device {
|
||||
data.address = 0x0;
|
||||
data.flags = 0x1; // Not free yet
|
||||
}
|
||||
|
||||
data.size = object->size;
|
||||
handleTable.erase(data.handle);
|
||||
|
||||
state.process->WriteMemory(data, buffer.output[0].address);
|
||||
}
|
||||
|
||||
@ -95,11 +105,13 @@ namespace skyline::service::nvdrv::device {
|
||||
Parameter parameter; // In
|
||||
u32 result; // Out
|
||||
} data = state.process->GetObject<Data>(buffer.input[0].address);
|
||||
|
||||
auto &object = handleTable.at(data.handle);
|
||||
switch (data.parameter) {
|
||||
case Parameter::Size:
|
||||
data.result = object->size;
|
||||
break;
|
||||
|
||||
case Parameter::Alignment:
|
||||
case Parameter::HeapMask:
|
||||
case Parameter::Kind: {
|
||||
@ -120,13 +132,16 @@ namespace skyline::service::nvdrv::device {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Parameter::Base:
|
||||
buffer.status = NvStatus::NotImplemented;
|
||||
break;
|
||||
|
||||
case Parameter::Compr:
|
||||
buffer.status = NvStatus::NotImplemented;
|
||||
break;
|
||||
}
|
||||
|
||||
state.process->WriteMemory(data, buffer.output[0].address);
|
||||
state.logger->Debug("Param: Input: Handle: 0x{:X}, Parameter: {}, Output: Result: 0x{:X}, Status: {}", data.handle, data.parameter, data.result, buffer.status);
|
||||
}
|
||||
@ -136,7 +151,9 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 id; // Out
|
||||
u32 handle; // In
|
||||
} data = state.process->GetObject<Data>(buffer.input[0].address);
|
||||
|
||||
data.id = handleTable.at(data.handle)->id;
|
||||
|
||||
state.process->WriteMemory(data, buffer.output[0].address);
|
||||
state.logger->Debug("GetId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
namespace skyline::service {
|
||||
ServiceManager::ServiceManager(const DeviceState &state) : state(state) {}
|
||||
|
||||
std::shared_ptr<BaseService> ServiceManager::CreateService(const Service serviceType) {
|
||||
std::shared_ptr<BaseService> ServiceManager::CreateService(Service serviceType) {
|
||||
auto serviceIter = serviceMap.find(serviceType);
|
||||
if (serviceIter != serviceMap.end())
|
||||
return (*serviceIter).second;
|
||||
@ -73,7 +73,7 @@ namespace skyline::service {
|
||||
return serviceObj;
|
||||
}
|
||||
|
||||
KHandle ServiceManager::NewSession(const Service serviceType) {
|
||||
KHandle ServiceManager::NewSession(Service serviceType) {
|
||||
std::lock_guard serviceGuard(mutex);
|
||||
return state.process->NewHandle<type::KSession>(CreateService(serviceType)).handle;
|
||||
}
|
||||
@ -110,7 +110,7 @@ namespace skyline::service {
|
||||
state.logger->Debug("Service has been registered: \"{}\" (0x{:X})", serviceObject->serviceName, handle);
|
||||
}
|
||||
|
||||
void ServiceManager::CloseSession(const KHandle handle) {
|
||||
void ServiceManager::CloseSession(KHandle handle) {
|
||||
std::lock_guard serviceGuard(mutex);
|
||||
auto session = state.process->GetHandle<type::KSession>(handle);
|
||||
if (session->serviceStatus == type::KSession::ServiceStatus::Open) {
|
||||
@ -124,7 +124,7 @@ namespace skyline::service {
|
||||
}
|
||||
};
|
||||
|
||||
void ServiceManager::SyncRequestHandler(const KHandle handle) {
|
||||
void ServiceManager::SyncRequestHandler(KHandle handle) {
|
||||
auto session = state.process->GetHandle<type::KSession>(handle);
|
||||
state.logger->Debug("----Start----");
|
||||
state.logger->Debug("Handle is 0x{:X}", handle);
|
||||
|
@ -22,7 +22,7 @@ namespace skyline::service {
|
||||
* @param serviceType The type of service requested
|
||||
* @return A shared pointer to an instance of the service
|
||||
*/
|
||||
std::shared_ptr<BaseService> CreateService(const Service serviceType);
|
||||
std::shared_ptr<BaseService> CreateService(Service serviceType);
|
||||
|
||||
public:
|
||||
/**
|
||||
@ -35,7 +35,7 @@ namespace skyline::service {
|
||||
* @param serviceType The type of the service
|
||||
* @return Handle to KService object of the service
|
||||
*/
|
||||
KHandle NewSession(const Service serviceType);
|
||||
KHandle NewSession(Service serviceType);
|
||||
|
||||
/**
|
||||
* @brief Creates a new service using it's type enum and writes it's handle or virtual handle (If it's a domain request) to IpcResponse
|
||||
@ -61,7 +61,7 @@ namespace skyline::service {
|
||||
* @note This only works for services created with `NewService` as sub-interfaces used with `RegisterService` can have multiple instances
|
||||
*/
|
||||
template<typename Type>
|
||||
inline std::shared_ptr<Type> GetService(const Service serviceType) {
|
||||
inline std::shared_ptr<Type> GetService(Service serviceType) {
|
||||
return std::static_pointer_cast<Type>(serviceMap.at(serviceType));
|
||||
}
|
||||
|
||||
@ -69,12 +69,12 @@ namespace skyline::service {
|
||||
* @brief Closes an existing session to a service
|
||||
* @param service The handle of the KService object
|
||||
*/
|
||||
void CloseSession(const KHandle handle);
|
||||
void CloseSession(KHandle handle);
|
||||
|
||||
/**
|
||||
* @brief Handles a Synchronous IPC Request
|
||||
* @param handle The handle of the object
|
||||
*/
|
||||
void SyncRequestHandler(const KHandle handle);
|
||||
void SyncRequestHandler(KHandle handle);
|
||||
};
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace skyline::service::settings {
|
||||
{0x3, SFUNC(ISystemSettingsServer::GetFirmwareVersion)}}) {}
|
||||
|
||||
void ISystemSettingsServer::GetFirmwareVersion(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
SysVerTitle title{.minor=9, .major=0, .micro=0, .revMajor=4, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
|
||||
SysVerTitle title{.major=9, .minor=0, .micro=0, .revMajor=4, .revMinor=0, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
|
||||
state.process->WriteMemory(title, request.outputBuf.at(0).address);
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ namespace skyline::service::sm {
|
||||
|
||||
void IUserInterface::GetService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
std::string serviceName(reinterpret_cast<char *>(request.cmdArg));
|
||||
|
||||
if (serviceName.empty()) {
|
||||
response.errorCode = constant::status::ServiceInvName;
|
||||
} else {
|
||||
|
@ -11,20 +11,22 @@ namespace skyline::service::timesrv {
|
||||
void ITimeZoneService::ToCalendarTimeWithMyRule(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
time_t curTime = std::time(nullptr);
|
||||
tm calender = *std::gmtime(&curTime);
|
||||
|
||||
CalendarTime calendarTime{
|
||||
.year = static_cast<u16>(calender.tm_year),
|
||||
.month = static_cast<u8>(calender.tm_mon),
|
||||
.day = static_cast<u8>(calender.tm_hour),
|
||||
.minute = static_cast<u8>(calender.tm_min),
|
||||
.second = static_cast<u8>(calender.tm_sec)
|
||||
.second = static_cast<u8>(calender.tm_sec),
|
||||
};
|
||||
response.Push(calendarTime);
|
||||
|
||||
CalendarAdditionalInfo calendarInfo{
|
||||
.dayWeek = static_cast<u32>(calender.tm_wday),
|
||||
.dayMonth = static_cast<u32>(calender.tm_mday),
|
||||
.name = *reinterpret_cast<const u64 *>(calender.tm_zone),
|
||||
.dst = static_cast<i32>(calender.tm_isdst),
|
||||
.utcRel = static_cast<u32>(calender.tm_gmtoff)
|
||||
.utcRel = static_cast<u32>(calender.tm_gmtoff),
|
||||
};
|
||||
response.Push(calendarInfo);
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ namespace skyline::service::visrv {
|
||||
std::string displayName(reinterpret_cast<char *>(request.cmdArg));
|
||||
state.logger->Debug("Setting display as: {}", displayName);
|
||||
state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>(Service::hosbinder_IHOSBinderDriver)->SetDisplay(displayName);
|
||||
|
||||
response.Push<u64>(0); // There's only one display
|
||||
}
|
||||
|
||||
@ -59,7 +60,9 @@ namespace skyline::service::visrv {
|
||||
u64 userId;
|
||||
} input = request.Pop<InputStruct>();
|
||||
state.logger->Debug("Opening Layer: Display Name: {}, Layer ID: {}, User ID: {}", input.displayName, input.layerId, input.userId);
|
||||
|
||||
std::string name(input.displayName);
|
||||
|
||||
Parcel parcel(state);
|
||||
LayerParcel data{
|
||||
.type = 0x20,
|
||||
@ -69,7 +72,8 @@ namespace skyline::service::visrv {
|
||||
};
|
||||
parcel.WriteData(data);
|
||||
parcel.objects.resize(4);
|
||||
response.Push(parcel.WriteParcel(request.outputBuf.at(0)));
|
||||
|
||||
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
||||
}
|
||||
|
||||
void IApplicationDisplayService::CloseLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
@ -87,12 +91,14 @@ namespace skyline::service::visrv {
|
||||
void IApplicationDisplayService::SetLayerScalingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto scalingMode = request.Pop<u64>();
|
||||
auto layerId = request.Pop<u64>();
|
||||
|
||||
state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", scalingMode, layerId);
|
||||
}
|
||||
|
||||
void IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
KHandle handle = state.process->InsertItem(state.gpu->vsyncEvent);
|
||||
state.logger->Debug("VSync Event Handle: 0x{:X}", handle);
|
||||
|
||||
response.copyHandles.push_back(handle);
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ namespace skyline::service::visrv {
|
||||
.string = "dispdrv"
|
||||
};
|
||||
parcel.WriteData(data);
|
||||
|
||||
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
||||
}
|
||||
|
||||
|
@ -18,19 +18,23 @@ namespace skyline::service::visrv {
|
||||
request.Skip<u32>();
|
||||
auto displayId = request.Pop<u64>();
|
||||
state.logger->Debug("Creating Managed Layer on Display: {}", displayId);
|
||||
|
||||
auto hosBinder = state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>(Service::hosbinder_IHOSBinderDriver);
|
||||
if (hosBinder->layerStatus != hosbinder::LayerStatus::Uninitialized)
|
||||
throw exception("The application is creating more than one layer");
|
||||
hosBinder->layerStatus = hosbinder::LayerStatus::Managed;
|
||||
|
||||
response.Push<u64>(0); // There's only one layer
|
||||
}
|
||||
|
||||
void IManagerDisplayService::DestroyManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto layerId = request.Pop<u64>();
|
||||
state.logger->Debug("Destroying Managed Layer: {}", layerId);
|
||||
|
||||
auto hosBinder = state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>(Service::hosbinder_IHOSBinderDriver);
|
||||
if (hosBinder->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
||||
state.logger->Warn("The application is destroying an uninitialized layer");
|
||||
|
||||
hosBinder->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
package emu.skyline
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
@ -114,6 +115,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
/**
|
||||
* This makes the window fullscreen then sets up [preferenceFd] and [logFd], sets up the performance statistics and finally calls [executeApplication] for executing the application
|
||||
*/
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user