Compare commits
78 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32f3b6b865 | ||
|
|
322349e8cc | ||
|
|
ebcee03b0c | ||
|
|
b70751ccb9 | ||
|
|
e48e9a406c | ||
|
|
0e15c68f54 | ||
|
|
b834c21894 | ||
|
|
d52ee6d0a7 | ||
|
|
dcfa1992ea | ||
|
|
b7f1095980 | ||
|
|
9aeada734d | ||
|
|
e87670ee48 | ||
|
|
1dbf71ceb3 | ||
|
|
9014861858 | ||
|
|
d1da7eb119 | ||
|
|
0832da3e40 | ||
|
|
3359e5ab70 | ||
|
|
4fbe4da911 | ||
|
|
4fb5ca80c0 | ||
|
|
5f75d97125 | ||
|
|
7791cc8c2e | ||
|
|
e8b2fd21d8 | ||
|
|
fbda5e9ec9 | ||
|
|
410ed82922 | ||
|
|
7afb7a9494 | ||
|
|
6694e11303 | ||
|
|
ab25d1fe9a | ||
|
|
5ec6a265bf | ||
|
|
7fb7540d69 | ||
|
|
d04abd39eb | ||
|
|
e371d12af6 | ||
|
|
994f497781 | ||
|
|
5d1447897a | ||
|
|
874be0e3e1 | ||
|
|
2b05c32343 | ||
|
|
b546640c41 | ||
|
|
5c4774e8ce | ||
|
|
3a85bc1e77 | ||
|
|
e13a91fa9b | ||
|
|
5502f39125 | ||
|
|
ba3dd7b78f | ||
|
|
afd0e2ee87 | ||
|
|
185bf3fd28 | ||
|
|
8758378dc4 | ||
|
|
102630f2b2 | ||
|
|
d88baa746b | ||
|
|
acc14d233f | ||
|
|
b00f4abe36 | ||
|
|
c47c3d723f | ||
|
|
3794c91145 | ||
|
|
01db5cf203 | ||
|
|
ba3916fc67 | ||
|
|
3fcc98e11a | ||
|
|
5b441fa25d | ||
|
|
8469b76630 | ||
|
|
b7cd5d742e | ||
|
|
56ecafc204 | ||
|
|
715f0c3b0c | ||
|
|
bba7e8ea4b | ||
|
|
e883101999 | ||
|
|
1889b641d9 | ||
|
|
6e37676482 | ||
|
|
5b6545b141 | ||
|
|
6f8a06bac5 | ||
|
|
aaf262bfed | ||
|
|
bcaadac22c | ||
|
|
be4fc777c0 | ||
|
|
908d3c5679 | ||
|
|
9a4beac95a | ||
|
|
622830f4e1 | ||
|
|
9ea8cffe35 | ||
|
|
f5110340e6 | ||
|
|
fc4d692c50 | ||
|
|
31c12de0fe | ||
|
|
70df449d0a | ||
|
|
43ce33b6cc | ||
|
|
24620bc4ea | ||
|
|
b178c9a349 |
@@ -4,9 +4,11 @@ parameters:
|
||||
version: ''
|
||||
|
||||
steps:
|
||||
- script: choco install vulkan-sdk
|
||||
displayName: 'Install vulkan-sdk'
|
||||
- script: python -m pip install --upgrade pip conan
|
||||
displayName: 'Install conan'
|
||||
- script: mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd ..
|
||||
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd ..
|
||||
displayName: 'Configure CMake'
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build'
|
||||
|
||||
@@ -66,6 +66,7 @@ else()
|
||||
-Wextra
|
||||
-Wmissing-declarations
|
||||
-Wno-attributes
|
||||
-Wno-invalid-offsetof
|
||||
-Wno-unused-parameter
|
||||
)
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream,
|
||||
return stream->GetTagsAndReleaseBuffers(max_count);
|
||||
}
|
||||
|
||||
std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream) {
|
||||
return stream->GetTagsAndReleaseBuffers();
|
||||
}
|
||||
|
||||
void AudioOut::StartStream(StreamPtr stream) {
|
||||
stream->Play();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ public:
|
||||
/// Returns a vector of recently released buffers specified by tag for the specified stream
|
||||
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count);
|
||||
|
||||
/// Returns a vector of all recently released buffers specified by tag for the specified stream
|
||||
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream);
|
||||
|
||||
/// Starts an audio stream for playback
|
||||
void StartStream(StreamPtr stream);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include "audio_core/audio_out.h"
|
||||
@@ -14,6 +15,59 @@
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] static constexpr s16 ClampToS16(s32 value) {
|
||||
return static_cast<s16>(std::clamp(value, s32{std::numeric_limits<s16>::min()},
|
||||
s32{std::numeric_limits<s16>::max()}));
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr s16 Mix2To1(s16 l_channel, s16 r_channel) {
|
||||
// Mix 50% from left and 50% from right channel
|
||||
constexpr float l_mix_amount = 50.0f / 100.0f;
|
||||
constexpr float r_mix_amount = 50.0f / 100.0f;
|
||||
return ClampToS16(static_cast<s32>((static_cast<float>(l_channel) * l_mix_amount) +
|
||||
(static_cast<float>(r_channel) * r_mix_amount)));
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(s16 fl_channel, s16 fr_channel,
|
||||
s16 fc_channel,
|
||||
[[maybe_unused]] s16 lf_channel,
|
||||
s16 bl_channel, s16 br_channel) {
|
||||
// Front channels are mixed 36.94%, Center channels are mixed to be 26.12% & the back channels
|
||||
// are mixed to be 36.94%
|
||||
|
||||
constexpr float front_mix_amount = 36.94f / 100.0f;
|
||||
constexpr float center_mix_amount = 26.12f / 100.0f;
|
||||
constexpr float back_mix_amount = 36.94f / 100.0f;
|
||||
|
||||
// Mix 50% from left and 50% from right channel
|
||||
const auto left = front_mix_amount * static_cast<float>(fl_channel) +
|
||||
center_mix_amount * static_cast<float>(fc_channel) +
|
||||
back_mix_amount * static_cast<float>(bl_channel);
|
||||
|
||||
const auto right = front_mix_amount * static_cast<float>(fr_channel) +
|
||||
center_mix_amount * static_cast<float>(fc_channel) +
|
||||
back_mix_amount * static_cast<float>(br_channel);
|
||||
|
||||
return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2WithCoefficients(
|
||||
s16 fl_channel, s16 fr_channel, s16 fc_channel, s16 lf_channel, s16 bl_channel, s16 br_channel,
|
||||
const std::array<float_le, 4>& coeff) {
|
||||
const auto left =
|
||||
static_cast<float>(fl_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
|
||||
static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(bl_channel) * coeff[0];
|
||||
|
||||
const auto right =
|
||||
static_cast<float>(fr_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
|
||||
static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(br_channel) * coeff[0];
|
||||
|
||||
return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace AudioCore {
|
||||
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
||||
AudioCommon::AudioRendererParameter params,
|
||||
@@ -62,10 +116,6 @@ Stream::State AudioRenderer::GetStreamState() const {
|
||||
return stream->GetState();
|
||||
}
|
||||
|
||||
static constexpr s16 ClampToS16(s32 value) {
|
||||
return static_cast<s16>(std::clamp(value, -32768, 32767));
|
||||
}
|
||||
|
||||
ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||
std::vector<u8>& output_params) {
|
||||
|
||||
@@ -104,8 +154,8 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param
|
||||
}
|
||||
}
|
||||
|
||||
auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
|
||||
splitter_context, effect_context);
|
||||
const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
|
||||
splitter_context, effect_context);
|
||||
|
||||
if (mix_result.IsError()) {
|
||||
LOG_ERROR(Audio, "Failed to update mix parameters");
|
||||
@@ -194,20 +244,22 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
|
||||
for (std::size_t i = 0; i < BUFFER_SIZE; i++) {
|
||||
if (channel_count == 1) {
|
||||
const auto sample = ClampToS16(mix_buffers[0][i]);
|
||||
buffer[i * stream_channel_count + 0] = sample;
|
||||
if (stream_channel_count > 1) {
|
||||
buffer[i * stream_channel_count + 1] = sample;
|
||||
|
||||
// Place sample in all channels
|
||||
for (u32 channel = 0; channel < stream_channel_count; channel++) {
|
||||
buffer[i * stream_channel_count + channel] = sample;
|
||||
}
|
||||
|
||||
if (stream_channel_count == 6) {
|
||||
buffer[i * stream_channel_count + 2] = sample;
|
||||
buffer[i * stream_channel_count + 4] = sample;
|
||||
buffer[i * stream_channel_count + 5] = sample;
|
||||
// Output stream has a LF channel, mute it!
|
||||
buffer[i * stream_channel_count + 3] = 0;
|
||||
}
|
||||
|
||||
} else if (channel_count == 2) {
|
||||
const auto l_sample = ClampToS16(mix_buffers[0][i]);
|
||||
const auto r_sample = ClampToS16(mix_buffers[1][i]);
|
||||
if (stream_channel_count == 1) {
|
||||
buffer[i * stream_channel_count + 0] = l_sample;
|
||||
buffer[i * stream_channel_count + 0] = Mix2To1(l_sample, r_sample);
|
||||
} else if (stream_channel_count == 2) {
|
||||
buffer[i * stream_channel_count + 0] = l_sample;
|
||||
buffer[i * stream_channel_count + 1] = r_sample;
|
||||
@@ -215,8 +267,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
|
||||
buffer[i * stream_channel_count + 0] = l_sample;
|
||||
buffer[i * stream_channel_count + 1] = r_sample;
|
||||
|
||||
buffer[i * stream_channel_count + 2] =
|
||||
ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2);
|
||||
// Combine both left and right channels to the center channel
|
||||
buffer[i * stream_channel_count + 2] = Mix2To1(l_sample, r_sample);
|
||||
|
||||
buffer[i * stream_channel_count + 4] = l_sample;
|
||||
buffer[i * stream_channel_count + 5] = r_sample;
|
||||
@@ -231,17 +283,25 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
|
||||
const auto br_sample = ClampToS16(mix_buffers[5][i]);
|
||||
|
||||
if (stream_channel_count == 1) {
|
||||
buffer[i * stream_channel_count + 0] = fc_sample;
|
||||
// Games seem to ignore the center channel half the time, we use the front left
|
||||
// and right channel for mixing as that's where majority of the audio goes
|
||||
buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample);
|
||||
} else if (stream_channel_count == 2) {
|
||||
buffer[i * stream_channel_count + 0] =
|
||||
static_cast<s16>(0.3694f * static_cast<float>(fl_sample) +
|
||||
0.2612f * static_cast<float>(fc_sample) +
|
||||
0.3694f * static_cast<float>(bl_sample));
|
||||
buffer[i * stream_channel_count + 1] =
|
||||
static_cast<s16>(0.3694f * static_cast<float>(fr_sample) +
|
||||
0.2612f * static_cast<float>(fc_sample) +
|
||||
0.3694f * static_cast<float>(br_sample));
|
||||
// Mix all channels into 2 channels
|
||||
if (sink_context.HasDownMixingCoefficients()) {
|
||||
const auto [left, right] = Mix6To2WithCoefficients(
|
||||
fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample,
|
||||
sink_context.GetDownmixCoefficients());
|
||||
buffer[i * stream_channel_count + 0] = left;
|
||||
buffer[i * stream_channel_count + 1] = right;
|
||||
} else {
|
||||
const auto [left, right] = Mix6To2(fl_sample, fr_sample, fc_sample,
|
||||
lf_sample, bl_sample, br_sample);
|
||||
buffer[i * stream_channel_count + 0] = left;
|
||||
buffer[i * stream_channel_count + 1] = right;
|
||||
}
|
||||
} else if (stream_channel_count == 6) {
|
||||
// Pass through
|
||||
buffer[i * stream_channel_count + 0] = fl_sample;
|
||||
buffer[i * stream_channel_count + 1] = fr_sample;
|
||||
buffer[i * stream_channel_count + 2] = fc_sample;
|
||||
@@ -259,7 +319,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
|
||||
}
|
||||
|
||||
void AudioRenderer::ReleaseAndQueueBuffers() {
|
||||
const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)};
|
||||
const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)};
|
||||
for (const auto& tag : released_buffers) {
|
||||
QueueMixedBuffer(tag);
|
||||
}
|
||||
|
||||
@@ -36,16 +36,10 @@ class Memory;
|
||||
}
|
||||
|
||||
namespace AudioCore {
|
||||
using DSPStateHolder = std::array<VoiceState*, 6>;
|
||||
using DSPStateHolder = std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>;
|
||||
|
||||
class AudioOut;
|
||||
|
||||
struct RendererInfo {
|
||||
u64_le elasped_frame_count{};
|
||||
INSERT_PADDING_WORDS(2);
|
||||
};
|
||||
static_assert(sizeof(RendererInfo) == 0x10, "RendererInfo is an invalid size");
|
||||
|
||||
class AudioRenderer {
|
||||
public:
|
||||
AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
||||
@@ -53,14 +47,14 @@ public:
|
||||
std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
|
||||
~AudioRenderer();
|
||||
|
||||
ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||
std::vector<u8>& output_params);
|
||||
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||
std::vector<u8>& output_params);
|
||||
void QueueMixedBuffer(Buffer::Tag tag);
|
||||
void ReleaseAndQueueBuffers();
|
||||
u32 GetSampleRate() const;
|
||||
u32 GetSampleCount() const;
|
||||
u32 GetMixBufferCount() const;
|
||||
Stream::State GetStreamState() const;
|
||||
[[nodiscard]] u32 GetSampleRate() const;
|
||||
[[nodiscard]] u32 GetSampleCount() const;
|
||||
[[nodiscard]] u32 GetMixBufferCount() const;
|
||||
[[nodiscard]] Stream::State GetStreamState() const;
|
||||
|
||||
private:
|
||||
BehaviorInfo behavior_info{};
|
||||
|
||||
@@ -43,22 +43,22 @@ public:
|
||||
void ClearError();
|
||||
void UpdateFlags(u64_le dest_flags);
|
||||
void SetUserRevision(u32_le revision);
|
||||
u32_le GetUserRevision() const;
|
||||
u32_le GetProcessRevision() const;
|
||||
[[nodiscard]] u32_le GetUserRevision() const;
|
||||
[[nodiscard]] u32_le GetProcessRevision() const;
|
||||
|
||||
bool IsAdpcmLoopContextBugFixed() const;
|
||||
bool IsSplitterSupported() const;
|
||||
bool IsLongSizePreDelaySupported() const;
|
||||
bool IsAudioRendererProcessingTimeLimit80PercentSupported() const;
|
||||
bool IsAudioRendererProcessingTimeLimit75PercentSupported() const;
|
||||
bool IsAudioRendererProcessingTimeLimit70PercentSupported() const;
|
||||
bool IsElapsedFrameCountSupported() const;
|
||||
bool IsMemoryPoolForceMappingEnabled() const;
|
||||
bool IsFlushVoiceWaveBuffersSupported() const;
|
||||
bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const;
|
||||
bool IsVoicePitchAndSrcSkippedSupported() const;
|
||||
bool IsMixInParameterDirtyOnlyUpdateSupported() const;
|
||||
bool IsSplitterBugFixed() const;
|
||||
[[nodiscard]] bool IsAdpcmLoopContextBugFixed() const;
|
||||
[[nodiscard]] bool IsSplitterSupported() const;
|
||||
[[nodiscard]] bool IsLongSizePreDelaySupported() const;
|
||||
[[nodiscard]] bool IsAudioRendererProcessingTimeLimit80PercentSupported() const;
|
||||
[[nodiscard]] bool IsAudioRendererProcessingTimeLimit75PercentSupported() const;
|
||||
[[nodiscard]] bool IsAudioRendererProcessingTimeLimit70PercentSupported() const;
|
||||
[[nodiscard]] bool IsElapsedFrameCountSupported() const;
|
||||
[[nodiscard]] bool IsMemoryPoolForceMappingEnabled() const;
|
||||
[[nodiscard]] bool IsFlushVoiceWaveBuffersSupported() const;
|
||||
[[nodiscard]] bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const;
|
||||
[[nodiscard]] bool IsVoicePitchAndSrcSkippedSupported() const;
|
||||
[[nodiscard]] bool IsMixInParameterDirtyOnlyUpdateSupported() const;
|
||||
[[nodiscard]] bool IsSplitterBugFixed() const;
|
||||
void CopyErrorInfo(OutParams& dst);
|
||||
|
||||
private:
|
||||
|
||||
@@ -39,13 +39,13 @@ public:
|
||||
void PreCommand();
|
||||
void PostCommand();
|
||||
|
||||
s32* GetChannelMixBuffer(s32 channel);
|
||||
const s32* GetChannelMixBuffer(s32 channel) const;
|
||||
s32* GetMixBuffer(std::size_t index);
|
||||
const s32* GetMixBuffer(std::size_t index) const;
|
||||
std::size_t GetMixChannelBufferOffset(s32 channel) const;
|
||||
[[nodiscard]] s32* GetChannelMixBuffer(s32 channel);
|
||||
[[nodiscard]] const s32* GetChannelMixBuffer(s32 channel) const;
|
||||
[[nodiscard]] s32* GetMixBuffer(std::size_t index);
|
||||
[[nodiscard]] const s32* GetMixBuffer(std::size_t index) const;
|
||||
[[nodiscard]] std::size_t GetMixChannelBufferOffset(s32 channel) const;
|
||||
|
||||
std::size_t GetTotalMixBufferCount() const;
|
||||
[[nodiscard]] std::size_t GetTotalMixBufferCount() const;
|
||||
|
||||
private:
|
||||
void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel);
|
||||
@@ -73,7 +73,7 @@ private:
|
||||
void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
|
||||
void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
|
||||
void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
|
||||
ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index);
|
||||
[[nodiscard]] ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index);
|
||||
|
||||
s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data,
|
||||
u32 sample_count, u32 write_offset, u32 write_count);
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr std::size_t MAX_CHANNEL_COUNT = 6;
|
||||
constexpr std::size_t MAX_WAVE_BUFFERS = 4;
|
||||
constexpr std::size_t MAX_SAMPLE_HISTORY = 4;
|
||||
constexpr u32 STREAM_SAMPLE_RATE = 48000;
|
||||
constexpr u32 STREAM_NUM_CHANNELS = 6;
|
||||
constexpr u32 STREAM_NUM_CHANNELS = 2;
|
||||
constexpr s32 NO_SPLITTER = -1;
|
||||
constexpr s32 NO_MIX = 0x7fffffff;
|
||||
constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min();
|
||||
|
||||
@@ -189,11 +189,11 @@ public:
|
||||
|
||||
virtual void Update(EffectInfo::InParams& in_params) = 0;
|
||||
virtual void UpdateForCommandGeneration() = 0;
|
||||
UsageState GetUsage() const;
|
||||
EffectType GetType() const;
|
||||
bool IsEnabled() const;
|
||||
s32 GetMixID() const;
|
||||
s32 GetProcessingOrder() const;
|
||||
[[nodiscard]] UsageState GetUsage() const;
|
||||
[[nodiscard]] EffectType GetType() const;
|
||||
[[nodiscard]] bool IsEnabled() const;
|
||||
[[nodiscard]] s32 GetMixID() const;
|
||||
[[nodiscard]] s32 GetProcessingOrder() const;
|
||||
|
||||
protected:
|
||||
UsageState usage{UsageState::Invalid};
|
||||
@@ -257,10 +257,10 @@ public:
|
||||
|
||||
void Update(EffectInfo::InParams& in_params) override;
|
||||
void UpdateForCommandGeneration() override;
|
||||
VAddr GetSendInfo() const;
|
||||
VAddr GetSendBuffer() const;
|
||||
VAddr GetRecvInfo() const;
|
||||
VAddr GetRecvBuffer() const;
|
||||
[[nodiscard]] VAddr GetSendInfo() const;
|
||||
[[nodiscard]] VAddr GetSendBuffer() const;
|
||||
[[nodiscard]] VAddr GetRecvInfo() const;
|
||||
[[nodiscard]] VAddr GetRecvBuffer() const;
|
||||
|
||||
private:
|
||||
VAddr send_info{};
|
||||
@@ -309,10 +309,10 @@ public:
|
||||
explicit EffectContext(std::size_t effect_count);
|
||||
~EffectContext();
|
||||
|
||||
std::size_t GetCount() const;
|
||||
EffectBase* GetInfo(std::size_t i);
|
||||
EffectBase* RetargetEffect(std::size_t i, EffectType effect);
|
||||
const EffectBase* GetInfo(std::size_t i) const;
|
||||
[[nodiscard]] std::size_t GetCount() const;
|
||||
[[nodiscard]] EffectBase* GetInfo(std::size_t i);
|
||||
[[nodiscard]] EffectBase* RetargetEffect(std::size_t i, EffectType effect);
|
||||
[[nodiscard]] const EffectBase* GetInfo(std::size_t i) const;
|
||||
|
||||
private:
|
||||
std::size_t effect_count{};
|
||||
|
||||
@@ -62,17 +62,17 @@ public:
|
||||
ServerMixInfo();
|
||||
~ServerMixInfo();
|
||||
|
||||
const ServerMixInfo::InParams& GetInParams() const;
|
||||
ServerMixInfo::InParams& GetInParams();
|
||||
[[nodiscard]] const ServerMixInfo::InParams& GetInParams() const;
|
||||
[[nodiscard]] ServerMixInfo::InParams& GetInParams();
|
||||
|
||||
bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
|
||||
BehaviorInfo& behavior_info, SplitterContext& splitter_context,
|
||||
EffectContext& effect_context);
|
||||
bool HasAnyConnection() const;
|
||||
[[nodiscard]] bool HasAnyConnection() const;
|
||||
void Cleanup();
|
||||
void SetEffectCount(std::size_t count);
|
||||
void ResetEffectProcessingOrder();
|
||||
s32 GetEffectOrder(std::size_t i) const;
|
||||
[[nodiscard]] s32 GetEffectOrder(std::size_t i) const;
|
||||
|
||||
private:
|
||||
std::vector<s32> effect_processing_order;
|
||||
@@ -91,15 +91,15 @@ public:
|
||||
void SortInfo();
|
||||
bool TsortInfo(SplitterContext& splitter_context);
|
||||
|
||||
std::size_t GetCount() const;
|
||||
ServerMixInfo& GetInfo(std::size_t i);
|
||||
const ServerMixInfo& GetInfo(std::size_t i) const;
|
||||
ServerMixInfo& GetSortedInfo(std::size_t i);
|
||||
const ServerMixInfo& GetSortedInfo(std::size_t i) const;
|
||||
ServerMixInfo& GetFinalMixInfo();
|
||||
const ServerMixInfo& GetFinalMixInfo() const;
|
||||
EdgeMatrix& GetEdgeMatrix();
|
||||
const EdgeMatrix& GetEdgeMatrix() const;
|
||||
[[nodiscard]] std::size_t GetCount() const;
|
||||
[[nodiscard]] ServerMixInfo& GetInfo(std::size_t i);
|
||||
[[nodiscard]] const ServerMixInfo& GetInfo(std::size_t i) const;
|
||||
[[nodiscard]] ServerMixInfo& GetSortedInfo(std::size_t i);
|
||||
[[nodiscard]] const ServerMixInfo& GetSortedInfo(std::size_t i) const;
|
||||
[[nodiscard]] ServerMixInfo& GetFinalMixInfo();
|
||||
[[nodiscard]] const ServerMixInfo& GetFinalMixInfo() const;
|
||||
[[nodiscard]] EdgeMatrix& GetEdgeMatrix();
|
||||
[[nodiscard]] const EdgeMatrix& GetEdgeMatrix() const;
|
||||
|
||||
private:
|
||||
void CalcMixBufferOffset();
|
||||
|
||||
@@ -12,10 +12,16 @@ std::size_t SinkContext::GetCount() const {
|
||||
return sink_count;
|
||||
}
|
||||
|
||||
void SinkContext::UpdateMainSink(SinkInfo::InParams& in) {
|
||||
void SinkContext::UpdateMainSink(const SinkInfo::InParams& in) {
|
||||
ASSERT(in.type == SinkTypes::Device);
|
||||
|
||||
has_downmix_coefs = in.device.down_matrix_enabled;
|
||||
if (has_downmix_coefs) {
|
||||
downmix_coefficients = in.device.down_matrix_coef;
|
||||
}
|
||||
in_use = in.in_use;
|
||||
use_count = in.device.input_count;
|
||||
std::memcpy(buffers.data(), in.device.input.data(), AudioCommon::MAX_CHANNEL_COUNT);
|
||||
buffers = in.device.input;
|
||||
}
|
||||
|
||||
bool SinkContext::InUse() const {
|
||||
@@ -28,4 +34,12 @@ std::vector<u8> SinkContext::OutputBuffers() const {
|
||||
return buffer_ret;
|
||||
}
|
||||
|
||||
bool SinkContext::HasDownMixingCoefficients() const {
|
||||
return has_downmix_coefs;
|
||||
}
|
||||
|
||||
const DownmixCoefficients& SinkContext::GetDownmixCoefficients() const {
|
||||
return downmix_coefficients;
|
||||
}
|
||||
|
||||
} // namespace AudioCore
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
using DownmixCoefficients = std::array<float_le, 4>;
|
||||
|
||||
enum class SinkTypes : u8 {
|
||||
Invalid = 0,
|
||||
Device = 1,
|
||||
@@ -50,7 +52,7 @@ public:
|
||||
std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input;
|
||||
INSERT_UNION_PADDING_BYTES(1);
|
||||
bool down_matrix_enabled;
|
||||
std::array<float_le, 4> down_matrix_coef;
|
||||
DownmixCoefficients down_matrix_coef;
|
||||
};
|
||||
static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size");
|
||||
|
||||
@@ -74,16 +76,21 @@ public:
|
||||
explicit SinkContext(std::size_t sink_count);
|
||||
~SinkContext();
|
||||
|
||||
std::size_t GetCount() const;
|
||||
[[nodiscard]] std::size_t GetCount() const;
|
||||
|
||||
void UpdateMainSink(SinkInfo::InParams& in);
|
||||
bool InUse() const;
|
||||
std::vector<u8> OutputBuffers() const;
|
||||
void UpdateMainSink(const SinkInfo::InParams& in);
|
||||
[[nodiscard]] bool InUse() const;
|
||||
[[nodiscard]] std::vector<u8> OutputBuffers() const;
|
||||
|
||||
[[nodiscard]] bool HasDownMixingCoefficients() const;
|
||||
[[nodiscard]] const DownmixCoefficients& GetDownmixCoefficients() const;
|
||||
|
||||
private:
|
||||
bool in_use{false};
|
||||
s32 use_count{};
|
||||
std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{};
|
||||
std::size_t sink_count{};
|
||||
bool has_downmix_coefs{false};
|
||||
DownmixCoefficients downmix_coefficients{};
|
||||
};
|
||||
} // namespace AudioCore
|
||||
|
||||
@@ -136,4 +136,14 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count)
|
||||
return tags;
|
||||
}
|
||||
|
||||
std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers() {
|
||||
std::vector<Buffer::Tag> tags;
|
||||
tags.reserve(released_buffers.size());
|
||||
while (!released_buffers.empty()) {
|
||||
tags.push_back(released_buffers.front()->GetTag());
|
||||
released_buffers.pop();
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
} // namespace AudioCore
|
||||
|
||||
@@ -57,37 +57,40 @@ public:
|
||||
bool QueueBuffer(BufferPtr&& buffer);
|
||||
|
||||
/// Returns true if the audio stream contains a buffer with the specified tag
|
||||
bool ContainsBuffer(Buffer::Tag tag) const;
|
||||
[[nodiscard]] bool ContainsBuffer(Buffer::Tag tag) const;
|
||||
|
||||
/// Returns a vector of recently released buffers specified by tag
|
||||
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count);
|
||||
[[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count);
|
||||
|
||||
/// Returns a vector of all recently released buffers specified by tag
|
||||
[[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers();
|
||||
|
||||
void SetVolume(float volume);
|
||||
|
||||
float GetVolume() const {
|
||||
[[nodiscard]] float GetVolume() const {
|
||||
return game_volume;
|
||||
}
|
||||
|
||||
/// Returns true if the stream is currently playing
|
||||
bool IsPlaying() const {
|
||||
[[nodiscard]] bool IsPlaying() const {
|
||||
return state == State::Playing;
|
||||
}
|
||||
|
||||
/// Returns the number of queued buffers
|
||||
std::size_t GetQueueSize() const {
|
||||
[[nodiscard]] std::size_t GetQueueSize() const {
|
||||
return queued_buffers.size();
|
||||
}
|
||||
|
||||
/// Gets the sample rate
|
||||
u32 GetSampleRate() const {
|
||||
[[nodiscard]] u32 GetSampleRate() const {
|
||||
return sample_rate;
|
||||
}
|
||||
|
||||
/// Gets the number of channels
|
||||
u32 GetNumChannels() const;
|
||||
[[nodiscard]] u32 GetNumChannels() const;
|
||||
|
||||
/// Get the state
|
||||
State GetState() const;
|
||||
[[nodiscard]] State GetState() const;
|
||||
|
||||
private:
|
||||
/// Plays the next queued buffer in the audio stream, starting playback if necessary
|
||||
@@ -97,7 +100,7 @@ private:
|
||||
void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {});
|
||||
|
||||
/// Gets the number of core cycles when the specified buffer will be released
|
||||
std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const;
|
||||
[[nodiscard]] std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const;
|
||||
|
||||
u32 sample_rate; ///< Sample rate of the stream
|
||||
Format format; ///< Format of the stream
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "common/logging/text_formatter.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Log {
|
||||
|
||||
@@ -152,10 +153,19 @@ FileBackend::FileBackend(const std::string& filename)
|
||||
void FileBackend::Write(const Entry& entry) {
|
||||
// prevent logs from going over the maximum size (in case its spamming and the user doesn't
|
||||
// know)
|
||||
constexpr std::size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L;
|
||||
if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) {
|
||||
constexpr std::size_t MAX_BYTES_WRITTEN = 100 * 1024 * 1024;
|
||||
constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1024 * 1024 * 1024;
|
||||
|
||||
if (!file.IsOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN_EXTENDED) {
|
||||
return;
|
||||
} else if (!Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n'));
|
||||
if (entry.log_level >= Level::Error) {
|
||||
file.Flush();
|
||||
@@ -222,6 +232,7 @@ void DebuggerBackend::Write(const Entry& entry) {
|
||||
SUB(Service, NPNS) \
|
||||
SUB(Service, NS) \
|
||||
SUB(Service, NVDRV) \
|
||||
SUB(Service, OLSC) \
|
||||
SUB(Service, PCIE) \
|
||||
SUB(Service, PCTL) \
|
||||
SUB(Service, PCV) \
|
||||
|
||||
@@ -95,6 +95,7 @@ enum class Class : ClassType {
|
||||
Service_NPNS, ///< The NPNS service
|
||||
Service_NS, ///< The NS services
|
||||
Service_NVDRV, ///< The NVDRV (Nvidia driver) service
|
||||
Service_OLSC, ///< The OLSC service
|
||||
Service_PCIE, ///< The PCIe service
|
||||
Service_PCTL, ///< The PCTL (Parental control) service
|
||||
Service_PCV, ///< The PCV service
|
||||
|
||||
@@ -458,6 +458,8 @@ add_library(core STATIC
|
||||
hle/service/nvflinger/buffer_queue.h
|
||||
hle/service/nvflinger/nvflinger.cpp
|
||||
hle/service/nvflinger/nvflinger.h
|
||||
hle/service/olsc/olsc.cpp
|
||||
hle/service/olsc/olsc.h
|
||||
hle/service/pcie/pcie.cpp
|
||||
hle/service/pcie/pcie.h
|
||||
hle/service/pctl/module.cpp
|
||||
|
||||
@@ -145,7 +145,7 @@ struct System::Impl {
|
||||
}
|
||||
|
||||
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
|
||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||
LOG_DEBUG(Core, "initialized OK");
|
||||
|
||||
device_memory = std::make_unique<Core::DeviceMemory>();
|
||||
|
||||
@@ -187,7 +187,7 @@ struct System::Impl {
|
||||
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
|
||||
|
||||
Service::Init(service_manager, system);
|
||||
services = std::make_unique<Service::Services>(service_manager, system);
|
||||
GDBStub::DeferStart();
|
||||
|
||||
interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system);
|
||||
@@ -208,9 +208,11 @@ struct System::Impl {
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
|
||||
const std::string& filepath) {
|
||||
app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
|
||||
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath,
|
||||
std::size_t program_index) {
|
||||
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
|
||||
program_index);
|
||||
|
||||
if (!app_loader) {
|
||||
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||
return ResultStatus::ErrorGetLoader;
|
||||
@@ -224,7 +226,7 @@ struct System::Impl {
|
||||
return init_result;
|
||||
}
|
||||
|
||||
telemetry_session->AddInitialInfo(*app_loader);
|
||||
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
|
||||
auto main_process =
|
||||
Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland);
|
||||
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
|
||||
@@ -296,7 +298,7 @@ struct System::Impl {
|
||||
|
||||
// Shutdown emulation session
|
||||
GDBStub::Shutdown();
|
||||
Service::Shutdown();
|
||||
services.reset();
|
||||
service_manager.reset();
|
||||
cheat_engine.reset();
|
||||
telemetry_session.reset();
|
||||
@@ -306,8 +308,8 @@ struct System::Impl {
|
||||
cpu_manager.Shutdown();
|
||||
|
||||
// Shutdown kernel and core timing
|
||||
kernel.Shutdown();
|
||||
core_timing.Shutdown();
|
||||
kernel.Shutdown();
|
||||
|
||||
// Close app loader
|
||||
app_loader.reset();
|
||||
@@ -338,7 +340,7 @@ struct System::Impl {
|
||||
Service::Glue::ApplicationLaunchProperty launch{};
|
||||
launch.title_id = process.GetTitleID();
|
||||
|
||||
FileSys::PatchManager pm{launch.title_id};
|
||||
FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};
|
||||
launch.version = pm.GetGameVersion().value_or(0);
|
||||
|
||||
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
|
||||
@@ -398,6 +400,9 @@ struct System::Impl {
|
||||
/// Service manager
|
||||
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
||||
|
||||
/// Services
|
||||
std::unique_ptr<Service::Services> services;
|
||||
|
||||
/// Telemetry session for this emulation session
|
||||
std::unique_ptr<Core::TelemetrySession> telemetry_session;
|
||||
|
||||
@@ -413,6 +418,8 @@ struct System::Impl {
|
||||
bool is_multicore{};
|
||||
bool is_async_gpu{};
|
||||
|
||||
ExecuteProgramCallback execute_program_callback;
|
||||
|
||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
|
||||
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};
|
||||
};
|
||||
@@ -444,8 +451,13 @@ void System::InvalidateCpuInstructionCaches() {
|
||||
impl->kernel.InvalidateAllInstructionCaches();
|
||||
}
|
||||
|
||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
|
||||
return impl->Load(*this, emu_window, filepath);
|
||||
void System::Shutdown() {
|
||||
impl->Shutdown();
|
||||
}
|
||||
|
||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
|
||||
std::size_t program_index) {
|
||||
return impl->Load(*this, emu_window, filepath, program_index);
|
||||
}
|
||||
|
||||
bool System::IsPoweredOn() const {
|
||||
@@ -632,7 +644,11 @@ const std::string& System::GetStatusDetails() const {
|
||||
return impl->status_details;
|
||||
}
|
||||
|
||||
Loader::AppLoader& System::GetAppLoader() const {
|
||||
Loader::AppLoader& System::GetAppLoader() {
|
||||
return *impl->app_loader;
|
||||
}
|
||||
|
||||
const Loader::AppLoader& System::GetAppLoader() const {
|
||||
return *impl->app_loader;
|
||||
}
|
||||
|
||||
@@ -748,14 +764,6 @@ const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const {
|
||||
return impl->build_id;
|
||||
}
|
||||
|
||||
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
|
||||
return impl->Init(*this, emu_window);
|
||||
}
|
||||
|
||||
void System::Shutdown() {
|
||||
impl->Shutdown();
|
||||
}
|
||||
|
||||
Service::SM::ServiceManager& System::ServiceManager() {
|
||||
return *impl->service_manager;
|
||||
}
|
||||
@@ -786,4 +794,16 @@ bool System::IsMulticore() const {
|
||||
return impl->is_multicore;
|
||||
}
|
||||
|
||||
void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) {
|
||||
impl->execute_program_callback = std::move(callback);
|
||||
}
|
||||
|
||||
void System::ExecuteProgram(std::size_t program_index) {
|
||||
if (impl->execute_program_callback) {
|
||||
impl->execute_program_callback(program_index);
|
||||
} else {
|
||||
LOG_CRITICAL(Core, "execute_program_callback must be initialized by the frontend");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
179
src/core/core.h
179
src/core/core.h
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -144,19 +145,19 @@ public:
|
||||
* Run the OS and Application
|
||||
* This function will start emulation and run the relevant devices
|
||||
*/
|
||||
ResultStatus Run();
|
||||
[[nodiscard]] ResultStatus Run();
|
||||
|
||||
/**
|
||||
* Pause the OS and Application
|
||||
* This function will pause emulation and stop the relevant devices
|
||||
*/
|
||||
ResultStatus Pause();
|
||||
[[nodiscard]] ResultStatus Pause();
|
||||
|
||||
/**
|
||||
* Step the CPU one instruction
|
||||
* @return Result status, indicating whether or not the operation succeeded.
|
||||
*/
|
||||
ResultStatus SingleStep();
|
||||
[[nodiscard]] ResultStatus SingleStep();
|
||||
|
||||
/**
|
||||
* Invalidate the CPU instruction caches
|
||||
@@ -173,22 +174,24 @@ public:
|
||||
* @param emu_window Reference to the host-system window used for video output and keyboard
|
||||
* input.
|
||||
* @param filepath String path to the executable application to load on the host file system.
|
||||
* @param program_index Specifies the index within the container of the program to launch.
|
||||
* @returns ResultStatus code, indicating if the operation succeeded.
|
||||
*/
|
||||
ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath);
|
||||
[[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
|
||||
std::size_t program_index = 0);
|
||||
|
||||
/**
|
||||
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
|
||||
* application).
|
||||
* @returns True if the emulated system is powered on, otherwise false.
|
||||
*/
|
||||
bool IsPoweredOn() const;
|
||||
[[nodiscard]] bool IsPoweredOn() const;
|
||||
|
||||
/// Gets a reference to the telemetry session for this emulation session.
|
||||
Core::TelemetrySession& TelemetrySession();
|
||||
[[nodiscard]] Core::TelemetrySession& TelemetrySession();
|
||||
|
||||
/// Gets a reference to the telemetry session for this emulation session.
|
||||
const Core::TelemetrySession& TelemetrySession() const;
|
||||
[[nodiscard]] const Core::TelemetrySession& TelemetrySession() const;
|
||||
|
||||
/// Prepare the core emulation for a reschedule
|
||||
void PrepareReschedule();
|
||||
@@ -197,185 +200,178 @@ public:
|
||||
void PrepareReschedule(u32 core_index);
|
||||
|
||||
/// Gets and resets core performance statistics
|
||||
PerfStatsResults GetAndResetPerfStats();
|
||||
[[nodiscard]] PerfStatsResults GetAndResetPerfStats();
|
||||
|
||||
/// Gets an ARM interface to the CPU core that is currently running
|
||||
ARM_Interface& CurrentArmInterface();
|
||||
[[nodiscard]] ARM_Interface& CurrentArmInterface();
|
||||
|
||||
/// Gets an ARM interface to the CPU core that is currently running
|
||||
const ARM_Interface& CurrentArmInterface() const;
|
||||
[[nodiscard]] const ARM_Interface& CurrentArmInterface() const;
|
||||
|
||||
/// Gets the index of the currently running CPU core
|
||||
std::size_t CurrentCoreIndex() const;
|
||||
[[nodiscard]] std::size_t CurrentCoreIndex() const;
|
||||
|
||||
/// Gets the scheduler for the CPU core that is currently running
|
||||
Kernel::Scheduler& CurrentScheduler();
|
||||
[[nodiscard]] Kernel::Scheduler& CurrentScheduler();
|
||||
|
||||
/// Gets the scheduler for the CPU core that is currently running
|
||||
const Kernel::Scheduler& CurrentScheduler() const;
|
||||
[[nodiscard]] const Kernel::Scheduler& CurrentScheduler() const;
|
||||
|
||||
/// Gets the physical core for the CPU core that is currently running
|
||||
Kernel::PhysicalCore& CurrentPhysicalCore();
|
||||
[[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore();
|
||||
|
||||
/// Gets the physical core for the CPU core that is currently running
|
||||
const Kernel::PhysicalCore& CurrentPhysicalCore() const;
|
||||
[[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const;
|
||||
|
||||
/// Gets a reference to an ARM interface for the CPU core with the specified index
|
||||
ARM_Interface& ArmInterface(std::size_t core_index);
|
||||
[[nodiscard]] ARM_Interface& ArmInterface(std::size_t core_index);
|
||||
|
||||
/// Gets a const reference to an ARM interface from the CPU core with the specified index
|
||||
const ARM_Interface& ArmInterface(std::size_t core_index) const;
|
||||
[[nodiscard]] const ARM_Interface& ArmInterface(std::size_t core_index) const;
|
||||
|
||||
CpuManager& GetCpuManager();
|
||||
/// Gets a reference to the underlying CPU manager.
|
||||
[[nodiscard]] CpuManager& GetCpuManager();
|
||||
|
||||
const CpuManager& GetCpuManager() const;
|
||||
/// Gets a const reference to the underlying CPU manager
|
||||
[[nodiscard]] const CpuManager& GetCpuManager() const;
|
||||
|
||||
/// Gets a reference to the exclusive monitor
|
||||
ExclusiveMonitor& Monitor();
|
||||
[[nodiscard]] ExclusiveMonitor& Monitor();
|
||||
|
||||
/// Gets a constant reference to the exclusive monitor
|
||||
const ExclusiveMonitor& Monitor() const;
|
||||
[[nodiscard]] const ExclusiveMonitor& Monitor() const;
|
||||
|
||||
/// Gets a mutable reference to the system memory instance.
|
||||
Core::Memory::Memory& Memory();
|
||||
[[nodiscard]] Core::Memory::Memory& Memory();
|
||||
|
||||
/// Gets a constant reference to the system memory instance.
|
||||
const Core::Memory::Memory& Memory() const;
|
||||
[[nodiscard]] const Core::Memory::Memory& Memory() const;
|
||||
|
||||
/// Gets a mutable reference to the GPU interface
|
||||
Tegra::GPU& GPU();
|
||||
[[nodiscard]] Tegra::GPU& GPU();
|
||||
|
||||
/// Gets an immutable reference to the GPU interface.
|
||||
const Tegra::GPU& GPU() const;
|
||||
[[nodiscard]] const Tegra::GPU& GPU() const;
|
||||
|
||||
/// Gets a mutable reference to the renderer.
|
||||
VideoCore::RendererBase& Renderer();
|
||||
[[nodiscard]] VideoCore::RendererBase& Renderer();
|
||||
|
||||
/// Gets an immutable reference to the renderer.
|
||||
const VideoCore::RendererBase& Renderer() const;
|
||||
[[nodiscard]] const VideoCore::RendererBase& Renderer() const;
|
||||
|
||||
/// Gets the scheduler for the CPU core with the specified index
|
||||
Kernel::Scheduler& Scheduler(std::size_t core_index);
|
||||
[[nodiscard]] Kernel::Scheduler& Scheduler(std::size_t core_index);
|
||||
|
||||
/// Gets the scheduler for the CPU core with the specified index
|
||||
const Kernel::Scheduler& Scheduler(std::size_t core_index) const;
|
||||
[[nodiscard]] const Kernel::Scheduler& Scheduler(std::size_t core_index) const;
|
||||
|
||||
/// Gets the global scheduler
|
||||
Kernel::GlobalScheduler& GlobalScheduler();
|
||||
[[nodiscard]] Kernel::GlobalScheduler& GlobalScheduler();
|
||||
|
||||
/// Gets the global scheduler
|
||||
const Kernel::GlobalScheduler& GlobalScheduler() const;
|
||||
[[nodiscard]] const Kernel::GlobalScheduler& GlobalScheduler() const;
|
||||
|
||||
/// Gets the manager for the guest device memory
|
||||
Core::DeviceMemory& DeviceMemory();
|
||||
[[nodiscard]] Core::DeviceMemory& DeviceMemory();
|
||||
|
||||
/// Gets the manager for the guest device memory
|
||||
const Core::DeviceMemory& DeviceMemory() const;
|
||||
[[nodiscard]] const Core::DeviceMemory& DeviceMemory() const;
|
||||
|
||||
/// Provides a pointer to the current process
|
||||
Kernel::Process* CurrentProcess();
|
||||
[[nodiscard]] Kernel::Process* CurrentProcess();
|
||||
|
||||
/// Provides a constant pointer to the current process.
|
||||
const Kernel::Process* CurrentProcess() const;
|
||||
[[nodiscard]] const Kernel::Process* CurrentProcess() const;
|
||||
|
||||
/// Provides a reference to the core timing instance.
|
||||
Timing::CoreTiming& CoreTiming();
|
||||
[[nodiscard]] Timing::CoreTiming& CoreTiming();
|
||||
|
||||
/// Provides a constant reference to the core timing instance.
|
||||
const Timing::CoreTiming& CoreTiming() const;
|
||||
[[nodiscard]] const Timing::CoreTiming& CoreTiming() const;
|
||||
|
||||
/// Provides a reference to the interrupt manager instance.
|
||||
Core::Hardware::InterruptManager& InterruptManager();
|
||||
[[nodiscard]] Core::Hardware::InterruptManager& InterruptManager();
|
||||
|
||||
/// Provides a constant reference to the interrupt manager instance.
|
||||
const Core::Hardware::InterruptManager& InterruptManager() const;
|
||||
[[nodiscard]] const Core::Hardware::InterruptManager& InterruptManager() const;
|
||||
|
||||
/// Provides a reference to the kernel instance.
|
||||
Kernel::KernelCore& Kernel();
|
||||
[[nodiscard]] Kernel::KernelCore& Kernel();
|
||||
|
||||
/// Provides a constant reference to the kernel instance.
|
||||
const Kernel::KernelCore& Kernel() const;
|
||||
[[nodiscard]] const Kernel::KernelCore& Kernel() const;
|
||||
|
||||
/// Provides a reference to the internal PerfStats instance.
|
||||
Core::PerfStats& GetPerfStats();
|
||||
[[nodiscard]] Core::PerfStats& GetPerfStats();
|
||||
|
||||
/// Provides a constant reference to the internal PerfStats instance.
|
||||
const Core::PerfStats& GetPerfStats() const;
|
||||
[[nodiscard]] const Core::PerfStats& GetPerfStats() const;
|
||||
|
||||
/// Provides a reference to the frame limiter;
|
||||
Core::FrameLimiter& FrameLimiter();
|
||||
[[nodiscard]] Core::FrameLimiter& FrameLimiter();
|
||||
|
||||
/// Provides a constant referent to the frame limiter
|
||||
const Core::FrameLimiter& FrameLimiter() const;
|
||||
[[nodiscard]] const Core::FrameLimiter& FrameLimiter() const;
|
||||
|
||||
/// Gets the name of the current game
|
||||
Loader::ResultStatus GetGameName(std::string& out) const;
|
||||
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
|
||||
|
||||
void SetStatus(ResultStatus new_status, const char* details);
|
||||
|
||||
const std::string& GetStatusDetails() const;
|
||||
[[nodiscard]] const std::string& GetStatusDetails() const;
|
||||
|
||||
Loader::AppLoader& GetAppLoader() const;
|
||||
[[nodiscard]] Loader::AppLoader& GetAppLoader();
|
||||
[[nodiscard]] const Loader::AppLoader& GetAppLoader() const;
|
||||
|
||||
Service::SM::ServiceManager& ServiceManager();
|
||||
const Service::SM::ServiceManager& ServiceManager() const;
|
||||
[[nodiscard]] Service::SM::ServiceManager& ServiceManager();
|
||||
[[nodiscard]] const Service::SM::ServiceManager& ServiceManager() const;
|
||||
|
||||
void SetFilesystem(FileSys::VirtualFilesystem vfs);
|
||||
|
||||
FileSys::VirtualFilesystem GetFilesystem() const;
|
||||
[[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const;
|
||||
|
||||
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
|
||||
const std::array<u8, 0x20>& build_id, VAddr main_region_begin,
|
||||
u64 main_region_size);
|
||||
|
||||
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
|
||||
|
||||
void SetDefaultAppletFrontendSet();
|
||||
|
||||
Service::AM::Applets::AppletManager& GetAppletManager();
|
||||
|
||||
const Service::AM::Applets::AppletManager& GetAppletManager() const;
|
||||
[[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager();
|
||||
[[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;
|
||||
|
||||
void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
|
||||
|
||||
FileSys::ContentProvider& GetContentProvider();
|
||||
[[nodiscard]] FileSys::ContentProvider& GetContentProvider();
|
||||
[[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const;
|
||||
|
||||
const FileSys::ContentProvider& GetContentProvider() const;
|
||||
|
||||
Service::FileSystem::FileSystemController& GetFileSystemController();
|
||||
|
||||
const Service::FileSystem::FileSystemController& GetFileSystemController() const;
|
||||
[[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController();
|
||||
[[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const;
|
||||
|
||||
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
|
||||
FileSys::ContentProvider* provider);
|
||||
|
||||
void ClearContentProvider(FileSys::ContentProviderUnionSlot slot);
|
||||
|
||||
const Reporter& GetReporter() const;
|
||||
[[nodiscard]] const Reporter& GetReporter() const;
|
||||
|
||||
Service::Glue::ARPManager& GetARPManager();
|
||||
[[nodiscard]] Service::Glue::ARPManager& GetARPManager();
|
||||
[[nodiscard]] const Service::Glue::ARPManager& GetARPManager() const;
|
||||
|
||||
const Service::Glue::ARPManager& GetARPManager() const;
|
||||
[[nodiscard]] Service::APM::Controller& GetAPMController();
|
||||
[[nodiscard]] const Service::APM::Controller& GetAPMController() const;
|
||||
|
||||
Service::APM::Controller& GetAPMController();
|
||||
[[nodiscard]] Service::LM::Manager& GetLogManager();
|
||||
[[nodiscard]] const Service::LM::Manager& GetLogManager() const;
|
||||
|
||||
const Service::APM::Controller& GetAPMController() const;
|
||||
|
||||
Service::LM::Manager& GetLogManager();
|
||||
|
||||
const Service::LM::Manager& GetLogManager() const;
|
||||
|
||||
Service::Time::TimeManager& GetTimeManager();
|
||||
|
||||
const Service::Time::TimeManager& GetTimeManager() const;
|
||||
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
|
||||
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
|
||||
|
||||
void SetExitLock(bool locked);
|
||||
|
||||
bool GetExitLock() const;
|
||||
[[nodiscard]] bool GetExitLock() const;
|
||||
|
||||
void SetCurrentProcessBuildID(const CurrentBuildProcessID& id);
|
||||
|
||||
const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
|
||||
[[nodiscard]] const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
|
||||
|
||||
/// Register a host thread as an emulated CPU Core.
|
||||
void RegisterCoreThread(std::size_t id);
|
||||
@@ -390,19 +386,28 @@ public:
|
||||
void ExitDynarmicProfile();
|
||||
|
||||
/// Tells if system is running on multicore.
|
||||
bool IsMulticore() const;
|
||||
[[nodiscard]] bool IsMulticore() const;
|
||||
|
||||
/// Type used for the frontend to designate a callback for System to re-launch the application
|
||||
/// using a specified program index.
|
||||
using ExecuteProgramCallback = std::function<void(std::size_t)>;
|
||||
|
||||
/**
|
||||
* Registers a callback from the frontend for System to re-launch the application using a
|
||||
* specified program index.
|
||||
* @param callback Callback from the frontend to relaunch the application.
|
||||
*/
|
||||
void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback);
|
||||
|
||||
/**
|
||||
* Instructs the frontend to re-launch the application using the specified program_index.
|
||||
* @param program_index Specifies the index within the application of the program to launch.
|
||||
*/
|
||||
void ExecuteProgram(std::size_t program_index);
|
||||
|
||||
private:
|
||||
System();
|
||||
|
||||
/**
|
||||
* Initialize the emulated system.
|
||||
* @param emu_window Reference to the host-system window used for video output and keyboard
|
||||
* input.
|
||||
* @return ResultStatus code, indicating if the operation succeeded.
|
||||
*/
|
||||
ResultStatus Init(Frontend::EmuWindow& emu_window);
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "common/fiber.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/core.h"
|
||||
@@ -343,6 +344,16 @@ void CpuManager::RunThread(std::size_t core) {
|
||||
data.initialized = true;
|
||||
const bool sc_sync = !is_async_gpu && !is_multicore;
|
||||
bool sc_sync_first_use = sc_sync;
|
||||
|
||||
// Cleanup
|
||||
SCOPE_EXIT({
|
||||
data.host_context->Exit();
|
||||
data.enter_barrier.reset();
|
||||
data.exit_barrier.reset();
|
||||
data.initialized = false;
|
||||
MicroProfileOnThreadExit();
|
||||
});
|
||||
|
||||
/// Running
|
||||
while (running_mode) {
|
||||
data.is_running = false;
|
||||
@@ -351,6 +362,12 @@ void CpuManager::RunThread(std::size_t core) {
|
||||
system.GPU().ObtainContext();
|
||||
sc_sync_first_use = false;
|
||||
}
|
||||
|
||||
// Abort if emulation was killed before the session really starts
|
||||
if (!system.IsPoweredOn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& scheduler = system.Kernel().CurrentScheduler();
|
||||
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
|
||||
data.is_running = true;
|
||||
@@ -360,13 +377,6 @@ void CpuManager::RunThread(std::size_t core) {
|
||||
data.exit_barrier->Wait();
|
||||
data.is_paused = false;
|
||||
}
|
||||
/// Time to cleanup
|
||||
data.host_context->Exit();
|
||||
data.enter_barrier.reset();
|
||||
data.exit_barrier.reset();
|
||||
data.initialized = false;
|
||||
|
||||
MicroProfileOnThreadExit();
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -29,7 +29,7 @@ constexpr std::array partition_names{
|
||||
"logo",
|
||||
};
|
||||
|
||||
XCI::XCI(VirtualFile file_)
|
||||
XCI::XCI(VirtualFile file_, std::size_t program_index)
|
||||
: file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
|
||||
partitions(partition_names.size()),
|
||||
partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
|
||||
@@ -62,7 +62,8 @@ XCI::XCI(VirtualFile file_)
|
||||
}
|
||||
|
||||
secure_partition = std::make_shared<NSP>(
|
||||
main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]));
|
||||
main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]),
|
||||
program_index);
|
||||
|
||||
ncas = secure_partition->GetNCAsCollapsed();
|
||||
program =
|
||||
|
||||
@@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo };
|
||||
|
||||
class XCI : public ReadOnlyVfsDirectory {
|
||||
public:
|
||||
explicit XCI(VirtualFile file);
|
||||
explicit XCI(VirtualFile file, std::size_t program_index = 0);
|
||||
~XCI() override;
|
||||
|
||||
Loader::ResultStatus GetStatus() const;
|
||||
|
||||
@@ -112,7 +112,10 @@ bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
|
||||
PatchManager::PatchManager(u64 title_id_,
|
||||
const Service::FileSystem::FileSystemController& fs_controller_,
|
||||
const ContentProvider& content_provider_)
|
||||
: title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
|
||||
|
||||
PatchManager::~PatchManager() = default;
|
||||
|
||||
@@ -128,34 +131,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
|
||||
if (Settings::values.dump_exefs) {
|
||||
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
|
||||
const auto dump_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
|
||||
const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id);
|
||||
if (dump_dir != nullptr) {
|
||||
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
|
||||
VfsRawCopyD(exefs, exefs_dir);
|
||||
}
|
||||
}
|
||||
|
||||
const auto& installed = Core::System::GetInstance().GetContentProvider();
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
const auto update_disabled =
|
||||
std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
|
||||
|
||||
// Game Updates
|
||||
const auto update_tid = GetUpdateTitleID(title_id);
|
||||
const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
|
||||
const auto update = content_provider.GetEntry(update_tid, ContentRecordType::Program);
|
||||
|
||||
if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr &&
|
||||
update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
|
||||
LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
|
||||
FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
|
||||
FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0)));
|
||||
exefs = update->GetExeFS();
|
||||
}
|
||||
|
||||
// LayeredExeFS
|
||||
const auto load_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||
if (load_dir != nullptr && load_dir->GetSize() > 0) {
|
||||
auto patch_dirs = load_dir->GetSubdirectories();
|
||||
std::sort(
|
||||
@@ -241,8 +240,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
|
||||
if (Settings::values.dump_nso) {
|
||||
LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,
|
||||
title_id);
|
||||
const auto dump_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
|
||||
const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id);
|
||||
if (dump_dir != nullptr) {
|
||||
const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
|
||||
const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id));
|
||||
@@ -254,8 +252,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
|
||||
|
||||
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
|
||||
|
||||
const auto load_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||
if (load_dir == nullptr) {
|
||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||
return nso;
|
||||
@@ -298,8 +295,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {
|
||||
|
||||
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
|
||||
|
||||
const auto load_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||
if (load_dir == nullptr) {
|
||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||
return false;
|
||||
@@ -313,8 +309,8 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {
|
||||
}
|
||||
|
||||
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
|
||||
const Core::System& system, const BuildID& build_id_) const {
|
||||
const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
const BuildID& build_id_) const {
|
||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||
if (load_dir == nullptr) {
|
||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||
return {};
|
||||
@@ -347,9 +343,9 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
|
||||
return out;
|
||||
}
|
||||
|
||||
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
|
||||
const auto load_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type,
|
||||
const Service::FileSystem::FileSystemController& fs_controller) {
|
||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||
if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
|
||||
load_dir == nullptr || load_dir->GetSize() <= 0) {
|
||||
return;
|
||||
@@ -411,19 +407,19 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
|
||||
const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}",
|
||||
title_id, static_cast<u8>(type));
|
||||
|
||||
if (type == ContentRecordType::Program || type == ContentRecordType::Data)
|
||||
if (type == ContentRecordType::Program || type == ContentRecordType::Data) {
|
||||
LOG_INFO(Loader, "{}", log_string);
|
||||
else
|
||||
} else {
|
||||
LOG_DEBUG(Loader, "{}", log_string);
|
||||
}
|
||||
|
||||
if (romfs == nullptr)
|
||||
if (romfs == nullptr) {
|
||||
return romfs;
|
||||
|
||||
const auto& installed = Core::System::GetInstance().GetContentProvider();
|
||||
}
|
||||
|
||||
// Game Updates
|
||||
const auto update_tid = GetUpdateTitleID(title_id);
|
||||
const auto update = installed.GetEntryRaw(update_tid, type);
|
||||
const auto update = content_provider.GetEntryRaw(update_tid, type);
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
const auto update_disabled =
|
||||
@@ -434,7 +430,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
|
||||
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
|
||||
new_nca->GetRomFS() != nullptr) {
|
||||
LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
|
||||
FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
|
||||
FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0)));
|
||||
romfs = new_nca->GetRomFS();
|
||||
}
|
||||
} else if (!update_disabled && update_raw != nullptr) {
|
||||
@@ -447,7 +443,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
|
||||
}
|
||||
|
||||
// LayeredFS
|
||||
ApplyLayeredFS(romfs, title_id, type);
|
||||
ApplyLayeredFS(romfs, title_id, type, fs_controller);
|
||||
|
||||
return romfs;
|
||||
}
|
||||
@@ -458,12 +454,11 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
|
||||
}
|
||||
|
||||
std::map<std::string, std::string, std::less<>> out;
|
||||
const auto& installed = Core::System::GetInstance().GetContentProvider();
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
|
||||
// Game Updates
|
||||
const auto update_tid = GetUpdateTitleID(title_id);
|
||||
PatchManager update{update_tid};
|
||||
PatchManager update{update_tid, fs_controller, content_provider};
|
||||
const auto metadata = update.GetControlMetadata();
|
||||
const auto& nacp = metadata.first;
|
||||
|
||||
@@ -474,8 +469,8 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
|
||||
if (nacp != nullptr) {
|
||||
out.insert_or_assign(update_label, nacp->GetVersionString());
|
||||
} else {
|
||||
if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
|
||||
const auto meta_ver = installed.GetEntryVersion(update_tid);
|
||||
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
|
||||
const auto meta_ver = content_provider.GetEntryVersion(update_tid);
|
||||
if (meta_ver.value_or(0) == 0) {
|
||||
out.insert_or_assign(update_label, "");
|
||||
} else {
|
||||
@@ -487,8 +482,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
|
||||
}
|
||||
|
||||
// General Mods (LayeredFS and IPS)
|
||||
const auto mod_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||
if (mod_dir != nullptr && mod_dir->GetSize() > 0) {
|
||||
for (const auto& mod : mod_dir->GetSubdirectories()) {
|
||||
std::string types;
|
||||
@@ -532,13 +526,15 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
|
||||
}
|
||||
|
||||
// DLC
|
||||
const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
|
||||
const auto dlc_entries =
|
||||
content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
|
||||
std::vector<ContentProviderEntry> dlc_match;
|
||||
dlc_match.reserve(dlc_entries.size());
|
||||
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
|
||||
[this, &installed](const ContentProviderEntry& entry) {
|
||||
[this](const ContentProviderEntry& entry) {
|
||||
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
|
||||
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
|
||||
content_provider.GetEntry(entry)->GetStatus() ==
|
||||
Loader::ResultStatus::Success;
|
||||
});
|
||||
if (!dlc_match.empty()) {
|
||||
// Ensure sorted so DLC IDs show in order.
|
||||
@@ -559,19 +555,16 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
|
||||
}
|
||||
|
||||
std::optional<u32> PatchManager::GetGameVersion() const {
|
||||
const auto& installed = Core::System::GetInstance().GetContentProvider();
|
||||
const auto update_tid = GetUpdateTitleID(title_id);
|
||||
if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
|
||||
return installed.GetEntryVersion(update_tid);
|
||||
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
|
||||
return content_provider.GetEntryVersion(update_tid);
|
||||
}
|
||||
|
||||
return installed.GetEntryVersion(title_id);
|
||||
return content_provider.GetEntryVersion(title_id);
|
||||
}
|
||||
|
||||
PatchManager::Metadata PatchManager::GetControlMetadata() const {
|
||||
const auto& installed = Core::System::GetInstance().GetContentProvider();
|
||||
|
||||
const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
|
||||
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
|
||||
if (base_control_nca == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -17,8 +17,13 @@ namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::FileSystem {
|
||||
class FileSystemController;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class ContentProvider;
|
||||
class NCA;
|
||||
class NACP;
|
||||
|
||||
@@ -29,7 +34,9 @@ public:
|
||||
using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>;
|
||||
using PatchVersionNames = std::map<std::string, std::string, std::less<>>;
|
||||
|
||||
explicit PatchManager(u64 title_id);
|
||||
explicit PatchManager(u64 title_id_,
|
||||
const Service::FileSystem::FileSystemController& fs_controller_,
|
||||
const ContentProvider& content_provider_);
|
||||
~PatchManager();
|
||||
|
||||
[[nodiscard]] u64 GetTitleID() const;
|
||||
@@ -50,7 +57,7 @@ public:
|
||||
|
||||
// Creates a CheatList object with all
|
||||
[[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList(
|
||||
const Core::System& system, const BuildID& build_id) const;
|
||||
const BuildID& build_id) const;
|
||||
|
||||
// Currently tracked RomFS patches:
|
||||
// - Game Updates
|
||||
@@ -80,6 +87,8 @@ private:
|
||||
const std::string& build_id) const;
|
||||
|
||||
u64 title_id;
|
||||
const Service::FileSystem::FileSystemController& fs_controller;
|
||||
const ContentProvider& content_provider;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -37,10 +37,12 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
|
||||
}
|
||||
|
||||
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
|
||||
if (!updatable)
|
||||
if (!updatable) {
|
||||
return MakeResult<VirtualFile>(file);
|
||||
}
|
||||
|
||||
const PatchManager patch_manager(current_process_title_id);
|
||||
const PatchManager patch_manager{current_process_title_id, filesystem_controller,
|
||||
content_provider};
|
||||
return MakeResult<VirtualFile>(
|
||||
patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
NSP::NSP(VirtualFile file_)
|
||||
: file(std::move(file_)), status{Loader::ResultStatus::Success},
|
||||
NSP::NSP(VirtualFile file_, std::size_t program_index)
|
||||
: file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success},
|
||||
pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
|
||||
if (pfs->GetStatus() != Loader::ResultStatus::Success) {
|
||||
status = pfs->GetStatus();
|
||||
@@ -146,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType
|
||||
if (extracted)
|
||||
LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
|
||||
|
||||
const auto title_id_iter = ncas.find(title_id);
|
||||
const auto title_id_iter = ncas.find(title_id + program_index);
|
||||
if (title_id_iter == ncas.end())
|
||||
return nullptr;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ enum class ContentRecordType : u8;
|
||||
|
||||
class NSP : public ReadOnlyVfsDirectory {
|
||||
public:
|
||||
explicit NSP(VirtualFile file);
|
||||
explicit NSP(VirtualFile file, std::size_t program_index = 0);
|
||||
~NSP() override;
|
||||
|
||||
Loader::ResultStatus GetStatus() const;
|
||||
@@ -69,6 +69,8 @@ private:
|
||||
|
||||
VirtualFile file;
|
||||
|
||||
const std::size_t program_index;
|
||||
|
||||
bool extracted = false;
|
||||
Loader::ResultStatus status;
|
||||
std::map<u64, Loader::ResultStatus> program_status;
|
||||
|
||||
@@ -102,8 +102,8 @@ public:
|
||||
float render_surface_scale = 1.0f;
|
||||
};
|
||||
|
||||
/// Polls window events
|
||||
virtual void PollEvents() = 0;
|
||||
/// Called from GPU thread when a frame is displayed.
|
||||
virtual void OnFrameDisplayed() {}
|
||||
|
||||
/**
|
||||
* Returns a GraphicsContext that the frontend provides to be used for rendering.
|
||||
|
||||
@@ -30,10 +30,12 @@ public:
|
||||
virtual StatusType GetStatus() const {
|
||||
return {};
|
||||
}
|
||||
virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const {
|
||||
virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
|
||||
return {};
|
||||
}
|
||||
virtual bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const {
|
||||
virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low,
|
||||
[[maybe_unused]] f32 amp_high,
|
||||
[[maybe_unused]] f32 freq_high) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -681,7 +681,7 @@ static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) {
|
||||
}
|
||||
|
||||
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
|
||||
static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) {
|
||||
static void OutputDebugString(Core::System& system, VAddr address, u64 len) {
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -742,8 +742,10 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
|
||||
bool is_locked = false;
|
||||
|
||||
if (res != Loader::ResultStatus::Success) {
|
||||
FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
|
||||
auto nacp_unique = pm.GetControlMetadata().first;
|
||||
const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(),
|
||||
system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
const auto nacp_unique = pm.GetControlMetadata().first;
|
||||
|
||||
if (nacp_unique != nullptr) {
|
||||
is_locked = nacp_unique->GetUserAccountSwitchLock();
|
||||
|
||||
@@ -246,9 +246,8 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
|
||||
|
||||
IDebugFunctions::~IDebugFunctions() = default;
|
||||
|
||||
ISelfController::ISelfController(Core::System& system,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
: ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) {
|
||||
ISelfController::ISelfController(Core::System& system, NVFlinger::NVFlinger& nvflinger)
|
||||
: ServiceFramework("ISelfController"), system(system), nvflinger(nvflinger) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISelfController::Exit, "Exit"},
|
||||
@@ -458,8 +457,8 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx)
|
||||
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
const auto display_id = nvflinger->OpenDisplay("Default");
|
||||
const auto layer_id = nvflinger->CreateLayer(*display_id);
|
||||
const auto display_id = nvflinger.OpenDisplay("Default");
|
||||
const auto layer_id = nvflinger.CreateLayer(*display_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -476,8 +475,8 @@ void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::HLERequestConte
|
||||
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
|
||||
// side effects.
|
||||
// TODO: Support multiple layers
|
||||
const auto display_id = nvflinger->OpenDisplay("Default");
|
||||
const auto layer_id = nvflinger->CreateLayer(*display_id);
|
||||
const auto display_id = nvflinger.OpenDisplay("Default");
|
||||
const auto layer_id = nvflinger.CreateLayer(*display_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -1189,9 +1188,9 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
|
||||
{110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
|
||||
{111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
|
||||
{120, nullptr, "ExecuteProgram"},
|
||||
{121, nullptr, "ClearUserChannel"},
|
||||
{122, nullptr, "UnpopToUserChannel"},
|
||||
{120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"},
|
||||
{121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"},
|
||||
{122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},
|
||||
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
|
||||
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
||||
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
|
||||
@@ -1381,13 +1380,16 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
|
||||
const auto res = [this] {
|
||||
const auto title_id = system.CurrentProcess()->GetTitleID();
|
||||
|
||||
FileSys::PatchManager pm{title_id};
|
||||
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
auto res = pm.GetControlMetadata();
|
||||
if (res.first != nullptr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)};
|
||||
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
|
||||
system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
return pm_update.GetControlMetadata();
|
||||
}();
|
||||
|
||||
@@ -1415,13 +1417,16 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
|
||||
const auto res = [this] {
|
||||
const auto title_id = system.CurrentProcess()->GetTitleID();
|
||||
|
||||
FileSys::PatchManager pm{title_id};
|
||||
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
auto res = pm.GetControlMetadata();
|
||||
if (res.first != nullptr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)};
|
||||
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
|
||||
system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
return pm_update.GetControlMetadata();
|
||||
}();
|
||||
|
||||
@@ -1556,6 +1561,34 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::ExecuteProgram(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
[[maybe_unused]] const auto unk_1 = rp.Pop<u32>();
|
||||
[[maybe_unused]] const auto unk_2 = rp.Pop<u32>();
|
||||
const auto program_index = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
system.ExecuteProgram(program_index);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::ClearUserChannel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::UnpopToUserChannel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
@@ -1580,8 +1613,8 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe
|
||||
rb.PushCopyObjects(friend_invitation_storage_channel_event.readable);
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
|
||||
Core::System& system) {
|
||||
auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel());
|
||||
// Needed on game boot
|
||||
message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||
|
||||
@@ -121,8 +121,7 @@ public:
|
||||
|
||||
class ISelfController final : public ServiceFramework<ISelfController> {
|
||||
public:
|
||||
explicit ISelfController(Core::System& system_,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger_);
|
||||
explicit ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_);
|
||||
~ISelfController() override;
|
||||
|
||||
private:
|
||||
@@ -156,7 +155,7 @@ private:
|
||||
};
|
||||
|
||||
Core::System& system;
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
NVFlinger::NVFlinger& nvflinger;
|
||||
Kernel::EventPair launchable_event;
|
||||
Kernel::EventPair accumulated_suspended_tick_changed_event;
|
||||
|
||||
@@ -288,6 +287,9 @@ private:
|
||||
void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
|
||||
void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);
|
||||
void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
|
||||
void ExecuteProgram(Kernel::HLERequestContext& ctx);
|
||||
void ClearUserChannel(Kernel::HLERequestContext& ctx);
|
||||
void UnpopToUserChannel(Kernel::HLERequestContext& ctx);
|
||||
void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx);
|
||||
void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
|
||||
void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx);
|
||||
@@ -332,7 +334,7 @@ public:
|
||||
};
|
||||
|
||||
/// Registers all AM services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system);
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
|
||||
Core::System& system);
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -13,10 +13,10 @@ namespace Service::AM {
|
||||
|
||||
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
|
||||
public:
|
||||
explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
explicit ILibraryAppletProxy(NVFlinger::NVFlinger& nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue,
|
||||
Core::System& system)
|
||||
: ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
|
||||
: ServiceFramework("ILibraryAppletProxy"), nvflinger(nvflinger),
|
||||
msg_queue(std::move(msg_queue)), system(system) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
@@ -109,16 +109,16 @@ private:
|
||||
rb.PushIpcInterface<IApplicationFunctions>(system);
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
NVFlinger::NVFlinger& nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
|
||||
public:
|
||||
explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
explicit ISystemAppletProxy(NVFlinger::NVFlinger& nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
|
||||
: ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
|
||||
: ServiceFramework("ISystemAppletProxy"), nvflinger(nvflinger),
|
||||
msg_queue(std::move(msg_queue)), system(system) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
@@ -220,7 +220,8 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationCreator>();
|
||||
}
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
|
||||
NVFlinger::NVFlinger& nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
Core::System& system;
|
||||
};
|
||||
@@ -249,10 +250,10 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
|
||||
}
|
||||
|
||||
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
|
||||
: ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)),
|
||||
msg_queue(std::move(msg_queue)), system(system) {
|
||||
AppletAE::AppletAE(NVFlinger::NVFlinger& nvflinger, std::shared_ptr<AppletMessageQueue> msg_queue,
|
||||
Core::System& system)
|
||||
: ServiceFramework("appletAE"), nvflinger(nvflinger), msg_queue(std::move(msg_queue)),
|
||||
system(system) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
|
||||
|
||||
@@ -23,7 +23,7 @@ class AppletMessageQueue;
|
||||
|
||||
class AppletAE final : public ServiceFramework<AppletAE> {
|
||||
public:
|
||||
explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
explicit AppletAE(NVFlinger::NVFlinger& nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
|
||||
~AppletAE() override;
|
||||
|
||||
@@ -34,7 +34,7 @@ private:
|
||||
void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx);
|
||||
void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
NVFlinger::NVFlinger& nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace Service::AM {
|
||||
|
||||
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
|
||||
public:
|
||||
explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
explicit IApplicationProxy(NVFlinger::NVFlinger& nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
|
||||
: ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)),
|
||||
: ServiceFramework("IApplicationProxy"), nvflinger(nvflinger),
|
||||
msg_queue(std::move(msg_queue)), system(system) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
@@ -98,7 +98,7 @@ private:
|
||||
rb.PushIpcInterface<IApplicationFunctions>(system);
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
NVFlinger::NVFlinger& nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
Core::System& system;
|
||||
};
|
||||
@@ -111,10 +111,10 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
|
||||
rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system);
|
||||
}
|
||||
|
||||
AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
|
||||
: ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)),
|
||||
msg_queue(std::move(msg_queue)), system(system) {
|
||||
AppletOE::AppletOE(NVFlinger::NVFlinger& nvflinger, std::shared_ptr<AppletMessageQueue> msg_queue,
|
||||
Core::System& system)
|
||||
: ServiceFramework("appletOE"), nvflinger(nvflinger), msg_queue(std::move(msg_queue)),
|
||||
system(system) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ class AppletMessageQueue;
|
||||
|
||||
class AppletOE final : public ServiceFramework<AppletOE> {
|
||||
public:
|
||||
explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
explicit AppletOE(NVFlinger::NVFlinger& nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
|
||||
~AppletOE() override;
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
private:
|
||||
void OpenApplicationProxy(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
NVFlinger::NVFlinger& nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
@@ -164,7 +164,8 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
const auto title_id = system.CurrentProcess()->GetTitleID();
|
||||
FileSys::PatchManager pm{title_id};
|
||||
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
|
||||
const auto res = pm.GetControlMetadata();
|
||||
if (res.first == nullptr) {
|
||||
|
||||
@@ -455,7 +455,9 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy
|
||||
const auto res = system.GetAppLoader().ReadControlData(nacp);
|
||||
|
||||
if (res != Loader::ResultStatus::Success) {
|
||||
FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
|
||||
const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(),
|
||||
system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
const auto metadata = pm.GetControlMetadata();
|
||||
const auto& nacp_unique = metadata.first;
|
||||
|
||||
@@ -728,7 +730,8 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
|
||||
void InstallInterfaces(Core::System& system) {
|
||||
std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter())
|
||||
std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetContentProvider(),
|
||||
system.GetReporter())
|
||||
->InstallAsService(system.ServiceManager());
|
||||
}
|
||||
|
||||
|
||||
@@ -650,8 +650,10 @@ private:
|
||||
u64 next_entry_index = 0;
|
||||
};
|
||||
|
||||
FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
|
||||
: ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) {
|
||||
FSP_SRV::FSP_SRV(FileSystemController& fsc_, const FileSys::ContentProvider& content_provider_,
|
||||
const Core::Reporter& reporter_)
|
||||
: ServiceFramework("fsp-srv"), fsc(fsc_), content_provider{content_provider_},
|
||||
reporter(reporter_) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "OpenFileSystem"},
|
||||
@@ -968,7 +970,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileSys::PatchManager pm{title_id};
|
||||
const FileSys::PatchManager pm{title_id, fsc, content_provider};
|
||||
|
||||
auto storage = std::make_shared<IStorage>(
|
||||
pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
|
||||
|
||||
@@ -12,8 +12,9 @@ class Reporter;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
class ContentProvider;
|
||||
class FileSystemBackend;
|
||||
}
|
||||
} // namespace FileSys
|
||||
|
||||
namespace Service::FileSystem {
|
||||
|
||||
@@ -32,7 +33,8 @@ enum class LogMode : u32 {
|
||||
|
||||
class FSP_SRV final : public ServiceFramework<FSP_SRV> {
|
||||
public:
|
||||
explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter);
|
||||
explicit FSP_SRV(FileSystemController& fsc_, const FileSys::ContentProvider& content_provider_,
|
||||
const Core::Reporter& reporter_);
|
||||
~FSP_SRV() override;
|
||||
|
||||
private:
|
||||
@@ -55,6 +57,7 @@ private:
|
||||
void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);
|
||||
|
||||
FileSystemController& fsc;
|
||||
const FileSys::ContentProvider& content_provider;
|
||||
|
||||
FileSys::VirtualFile romfs;
|
||||
u64 current_process_id = 0;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
@@ -29,8 +30,8 @@ IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountPro
|
||||
|
||||
IAccountProxyInterface::~IAccountProxyInterface() = default;
|
||||
|
||||
IApplicationManagerInterface::IApplicationManagerInterface()
|
||||
: ServiceFramework{"IApplicationManagerInterface"} {
|
||||
IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_)
|
||||
: ServiceFramework{"IApplicationManagerInterface"}, system{system_} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "ListApplicationRecord"},
|
||||
@@ -298,7 +299,8 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC
|
||||
|
||||
const auto size = ctx.GetWriteBufferSize();
|
||||
|
||||
const FileSys::PatchManager pm{title_id};
|
||||
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
const auto control = pm.GetControlMetadata();
|
||||
|
||||
std::vector<u8> out;
|
||||
@@ -538,14 +540,14 @@ IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface()
|
||||
|
||||
IFactoryResetInterface::~IFactoryResetInterface() = default;
|
||||
|
||||
NS::NS(const char* name) : ServiceFramework{name} {
|
||||
NS::NS(const char* name, Core::System& system_) : ServiceFramework{name}, system{system_} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
|
||||
{7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
|
||||
{7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
|
||||
{7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
|
||||
{7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
|
||||
{7996, &NS::PushIApplicationManagerInterface, "GetApplicationManagerInterface"},
|
||||
{7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
|
||||
{7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"},
|
||||
{7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
|
||||
@@ -558,7 +560,7 @@ NS::NS(const char* name) : ServiceFramework{name} {
|
||||
NS::~NS() = default;
|
||||
|
||||
std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const {
|
||||
return GetInterface<IApplicationManagerInterface>();
|
||||
return GetInterface<IApplicationManagerInterface>(system);
|
||||
}
|
||||
|
||||
class NS_DEV final : public ServiceFramework<NS_DEV> {
|
||||
@@ -678,11 +680,11 @@ public:
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
|
||||
|
||||
std::make_shared<NS>("ns:am2")->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:ec")->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:rid")->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:rt")->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:web")->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:am2", system)->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:ec", system)->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager);
|
||||
|
||||
std::make_shared<NS_DEV>()->InstallAsService(service_manager);
|
||||
std::make_shared<NS_SU>()->InstallAsService(service_manager);
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service {
|
||||
|
||||
namespace FileSystem {
|
||||
@@ -22,7 +26,7 @@ public:
|
||||
|
||||
class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
|
||||
public:
|
||||
explicit IApplicationManagerInterface();
|
||||
explicit IApplicationManagerInterface(Core::System& system_);
|
||||
~IApplicationManagerInterface() override;
|
||||
|
||||
ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages);
|
||||
@@ -32,6 +36,8 @@ private:
|
||||
void GetApplicationControlData(Kernel::HLERequestContext& ctx);
|
||||
void GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx);
|
||||
void ConvertApplicationLanguageToLanguageCode(Kernel::HLERequestContext& ctx);
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
|
||||
@@ -72,13 +78,13 @@ public:
|
||||
|
||||
class NS final : public ServiceFramework<NS> {
|
||||
public:
|
||||
explicit NS(const char* name);
|
||||
explicit NS(const char* name, Core::System& system_);
|
||||
~NS() override;
|
||||
|
||||
std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
template <typename T, typename... Args>
|
||||
void PushInterface(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NS, "called");
|
||||
|
||||
@@ -87,13 +93,23 @@ private:
|
||||
rb.PushIpcInterface<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetInterface() const {
|
||||
void PushIApplicationManagerInterface(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NS, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationManagerInterface>(system);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
std::shared_ptr<T> GetInterface(Args&&... args) const {
|
||||
static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>,
|
||||
"Not a base of ServiceFrameworkBase");
|
||||
|
||||
return std::make_shared<T>();
|
||||
return std::make_shared<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
/// Registers all NS services with the specified service manager.
|
||||
|
||||
@@ -24,25 +24,38 @@ public:
|
||||
explicit nvdevice(Core::System& system) : system{system} {}
|
||||
virtual ~nvdevice() = default;
|
||||
|
||||
union Ioctl {
|
||||
u32_le raw;
|
||||
BitField<0, 8, u32> cmd;
|
||||
BitField<8, 8, u32> group;
|
||||
BitField<16, 14, u32> length;
|
||||
BitField<30, 1, u32> is_in;
|
||||
BitField<31, 1, u32> is_out;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an ioctl request.
|
||||
* Handles an ioctl1 request.
|
||||
* @param command The ioctl command id.
|
||||
* @param input A buffer containing the input data for the ioctl.
|
||||
* @param output A buffer where the output data will be written to.
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) = 0;
|
||||
virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) = 0;
|
||||
|
||||
/**
|
||||
* Handles an ioctl2 request.
|
||||
* @param command The ioctl command id.
|
||||
* @param input A buffer containing the input data for the ioctl.
|
||||
* @param inline_input A buffer containing the input data for the ioctl which has been inlined.
|
||||
* @param output A buffer where the output data will be written to.
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) = 0;
|
||||
|
||||
/**
|
||||
* Handles an ioctl3 request.
|
||||
* @param command The ioctl command id.
|
||||
* @param input A buffer containing the input data for the ioctl.
|
||||
* @param output A buffer where the output data will be written to.
|
||||
* @param inline_output A buffer where the inlined output data will be written to.
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) = 0;
|
||||
|
||||
protected:
|
||||
Core::System& system;
|
||||
|
||||
@@ -18,11 +18,23 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de
|
||||
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
||||
nvdisp_disp0 ::~nvdisp_disp0() = default;
|
||||
|
||||
u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
return 0;
|
||||
NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
|
||||
|
||||
@@ -20,9 +20,13 @@ public:
|
||||
explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvdisp_disp0() override;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
|
||||
/// Performs a screen flip, drawing the buffer pointed to by the handle.
|
||||
void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
|
||||
|
||||
@@ -17,59 +17,78 @@
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
|
||||
namespace NvErrCodes {
|
||||
constexpr u32 Success{};
|
||||
constexpr u32 OutOfMemory{static_cast<u32>(-12)};
|
||||
constexpr u32 InvalidInput{static_cast<u32>(-22)};
|
||||
} // namespace NvErrCodes
|
||||
|
||||
nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
|
||||
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
||||
nvhost_as_gpu::~nvhost_as_gpu() = default;
|
||||
|
||||
u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
||||
command.raw, input.size(), output.size());
|
||||
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocInitalizeExCommand:
|
||||
return InitalizeEx(input, output);
|
||||
case IoctlCommand::IocAllocateSpaceCommand:
|
||||
return AllocateSpace(input, output);
|
||||
case IoctlCommand::IocMapBufferExCommand:
|
||||
return MapBufferEx(input, output);
|
||||
case IoctlCommand::IocBindChannelCommand:
|
||||
return BindChannel(input, output);
|
||||
case IoctlCommand::IocGetVaRegionsCommand:
|
||||
return GetVARegions(input, output);
|
||||
case IoctlCommand::IocUnmapBufferCommand:
|
||||
return UnmapBuffer(input, output);
|
||||
case IoctlCommand::IocFreeSpaceCommand:
|
||||
return FreeSpace(input, output);
|
||||
NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 'A':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return BindChannel(input, output);
|
||||
case 0x2:
|
||||
return AllocateSpace(input, output);
|
||||
case 0x3:
|
||||
return FreeSpace(input, output);
|
||||
case 0x5:
|
||||
return UnmapBuffer(input, output);
|
||||
case 0x6:
|
||||
return MapBufferEx(input, output);
|
||||
case 0x8:
|
||||
return GetVARegions(input, output);
|
||||
case 0x9:
|
||||
return InitalizeEx(input, output);
|
||||
case 0x14:
|
||||
return Remap(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) {
|
||||
return Remap(input, output);
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl command");
|
||||
return 0;
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 'A':
|
||||
switch (command.cmd) {
|
||||
case 0x8:
|
||||
return GetVARegions(input, output, inline_output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlInitalizeEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
|
||||
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlAllocSpace params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -83,17 +102,17 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
|
||||
params.offset = system.GPU().MemoryManager().Allocate(size, params.align);
|
||||
}
|
||||
|
||||
auto result{NvErrCodes::Success};
|
||||
auto result = NvResult::Success;
|
||||
if (!params.offset) {
|
||||
LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size);
|
||||
result = NvErrCodes::OutOfMemory;
|
||||
result = NvResult::InsufficientMemory;
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlFreeSpace params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -104,15 +123,15 @@ u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& outp
|
||||
static_cast<std::size_t>(params.pages) * params.page_size);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvErrCodes::Success;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
|
||||
|
||||
auto result{NvErrCodes::Success};
|
||||
auto result = NvResult::Success;
|
||||
std::vector<IoctlRemapEntry> entries(num_entries);
|
||||
std::memcpy(entries.data(), input.data(), input.size());
|
||||
|
||||
@@ -123,7 +142,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
|
||||
const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};
|
||||
if (!object) {
|
||||
LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle);
|
||||
result = NvErrCodes::InvalidInput;
|
||||
result = NvResult::InvalidState;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -134,7 +153,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
|
||||
|
||||
if (!addr) {
|
||||
LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!");
|
||||
result = NvErrCodes::InvalidInput;
|
||||
result = NvResult::InvalidState;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -143,7 +162,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlMapBufferEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -157,7 +176,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
if (!object) {
|
||||
LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvErrCodes::InvalidInput;
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
|
||||
// The real nvservices doesn't make a distinction between handles and ids, and
|
||||
@@ -184,16 +203,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
params.mapping_size, params.offset);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvErrCodes::InvalidInput;
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvErrCodes::Success;
|
||||
return NvResult::Success;
|
||||
} else {
|
||||
LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvErrCodes::InvalidInput;
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,10 +232,10 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size);
|
||||
}
|
||||
|
||||
auto result{NvErrCodes::Success};
|
||||
auto result = NvResult::Success;
|
||||
if (!params.offset) {
|
||||
LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size);
|
||||
result = NvErrCodes::InvalidInput;
|
||||
result = NvResult::InvalidState;
|
||||
} else {
|
||||
AddBufferMap(params.offset, size, physical_address, is_alloc);
|
||||
}
|
||||
@@ -225,7 +244,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlUnmapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -238,20 +257,19 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvErrCodes::Success;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlBindChannel params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd);
|
||||
|
||||
channel = params.fd;
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlGetVaRegions params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -270,7 +288,31 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o
|
||||
// TODO(ogniK): This probably can stay stubbed but should add support way way later
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) {
|
||||
IoctlGetVaRegions params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
|
||||
params.buf_size);
|
||||
|
||||
params.buf_size = 0x30;
|
||||
params.regions[0].offset = 0x04000000;
|
||||
params.regions[0].page_size = 0x1000;
|
||||
params.regions[0].pages = 0x3fbfff;
|
||||
|
||||
params.regions[1].offset = 0x04000000;
|
||||
params.regions[1].page_size = 0x10000;
|
||||
params.regions[1].pages = 0x1bffff;
|
||||
|
||||
// TODO(ogniK): This probably can stay stubbed but should add support way way later
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
std::memcpy(inline_output.data(), ¶ms.regions, inline_output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const {
|
||||
|
||||
@@ -30,9 +30,13 @@ public:
|
||||
explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvhost_as_gpu() override;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
|
||||
private:
|
||||
class BufferMap final {
|
||||
@@ -74,32 +78,21 @@ private:
|
||||
bool is_allocated{};
|
||||
};
|
||||
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocInitalizeExCommand = 0x40284109,
|
||||
IocAllocateSpaceCommand = 0xC0184102,
|
||||
IocRemapCommand = 0x00000014,
|
||||
IocMapBufferExCommand = 0xC0284106,
|
||||
IocBindChannelCommand = 0x40044101,
|
||||
IocGetVaRegionsCommand = 0xC0404108,
|
||||
IocUnmapBufferCommand = 0xC0084105,
|
||||
IocFreeSpaceCommand = 0xC0104103,
|
||||
};
|
||||
|
||||
struct IoctlInitalizeEx {
|
||||
u32_le big_page_size; // depends on GPU's available_big_page_sizes; 0=default
|
||||
s32_le as_fd; // ignored; passes 0
|
||||
u32_le flags; // passes 0
|
||||
u32_le reserved; // ignored; passes 0
|
||||
u64_le unk0;
|
||||
u64_le unk1;
|
||||
u64_le unk2;
|
||||
u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default
|
||||
s32_le as_fd{}; // ignored; passes 0
|
||||
u32_le flags{}; // passes 0
|
||||
u32_le reserved{}; // ignored; passes 0
|
||||
u64_le unk0{};
|
||||
u64_le unk1{};
|
||||
u64_le unk2{};
|
||||
};
|
||||
static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size");
|
||||
|
||||
struct IoctlAllocSpace {
|
||||
u32_le pages;
|
||||
u32_le page_size;
|
||||
AddressSpaceFlags flags;
|
||||
u32_le pages{};
|
||||
u32_le page_size{};
|
||||
AddressSpaceFlags flags{};
|
||||
INSERT_PADDING_WORDS(1);
|
||||
union {
|
||||
u64_le offset;
|
||||
@@ -109,70 +102,73 @@ private:
|
||||
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
|
||||
|
||||
struct IoctlFreeSpace {
|
||||
u64_le offset;
|
||||
u32_le pages;
|
||||
u32_le page_size;
|
||||
u64_le offset{};
|
||||
u32_le pages{};
|
||||
u32_le page_size{};
|
||||
};
|
||||
static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
|
||||
|
||||
struct IoctlRemapEntry {
|
||||
u16_le flags;
|
||||
u16_le kind;
|
||||
u32_le nvmap_handle;
|
||||
u32_le map_offset;
|
||||
u32_le offset;
|
||||
u32_le pages;
|
||||
u16_le flags{};
|
||||
u16_le kind{};
|
||||
u32_le nvmap_handle{};
|
||||
u32_le map_offset{};
|
||||
u32_le offset{};
|
||||
u32_le pages{};
|
||||
};
|
||||
static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
|
||||
|
||||
struct IoctlMapBufferEx {
|
||||
AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable
|
||||
u32_le kind; // -1 is default
|
||||
u32_le nvmap_handle;
|
||||
u32_le page_size; // 0 means don't care
|
||||
s64_le buffer_offset;
|
||||
u64_le mapping_size;
|
||||
s64_le offset;
|
||||
AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable
|
||||
u32_le kind{}; // -1 is default
|
||||
u32_le nvmap_handle{};
|
||||
u32_le page_size{}; // 0 means don't care
|
||||
s64_le buffer_offset{};
|
||||
u64_le mapping_size{};
|
||||
s64_le offset{};
|
||||
};
|
||||
static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");
|
||||
|
||||
struct IoctlUnmapBuffer {
|
||||
s64_le offset;
|
||||
s64_le offset{};
|
||||
};
|
||||
static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");
|
||||
|
||||
struct IoctlBindChannel {
|
||||
u32_le fd;
|
||||
s32_le fd{};
|
||||
};
|
||||
static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size");
|
||||
|
||||
struct IoctlVaRegion {
|
||||
u64_le offset;
|
||||
u32_le page_size;
|
||||
u64_le offset{};
|
||||
u32_le page_size{};
|
||||
INSERT_PADDING_WORDS(1);
|
||||
u64_le pages;
|
||||
u64_le pages{};
|
||||
};
|
||||
static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size");
|
||||
|
||||
struct IoctlGetVaRegions {
|
||||
u64_le buf_addr; // (contained output user ptr on linux, ignored)
|
||||
u32_le buf_size; // forced to 2*sizeof(struct va_region)
|
||||
u32_le reserved;
|
||||
IoctlVaRegion regions[2];
|
||||
u64_le buf_addr{}; // (contained output user ptr on linux, ignored)
|
||||
u32_le buf_size{}; // forced to 2*sizeof(struct va_region)
|
||||
u32_le reserved{};
|
||||
IoctlVaRegion regions[2]{};
|
||||
};
|
||||
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
|
||||
"IoctlGetVaRegions is incorrect size");
|
||||
|
||||
u32 channel{};
|
||||
s32 channel{};
|
||||
|
||||
u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 Remap(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output);
|
||||
|
||||
std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
|
||||
void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
|
||||
|
||||
@@ -20,41 +20,56 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,
|
||||
: nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
|
||||
nvhost_ctrl::~nvhost_ctrl() = default;
|
||||
|
||||
u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
||||
command.raw, input.size(), output.size());
|
||||
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocGetConfigCommand:
|
||||
return NvOsGetConfigU32(input, output);
|
||||
case IoctlCommand::IocCtrlEventWaitCommand:
|
||||
return IocCtrlEventWait(input, output, false, ctrl);
|
||||
case IoctlCommand::IocCtrlEventWaitAsyncCommand:
|
||||
return IocCtrlEventWait(input, output, true, ctrl);
|
||||
case IoctlCommand::IocCtrlEventRegisterCommand:
|
||||
return IocCtrlEventRegister(input, output);
|
||||
case IoctlCommand::IocCtrlEventUnregisterCommand:
|
||||
return IocCtrlEventUnregister(input, output);
|
||||
case IoctlCommand::IocCtrlClearEventWaitCommand:
|
||||
return IocCtrlClearEventWait(input, output);
|
||||
NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
case 0x1b:
|
||||
return NvOsGetConfigU32(input, output);
|
||||
case 0x1c:
|
||||
return IocCtrlClearEventWait(input, output);
|
||||
case 0x1d:
|
||||
return IocCtrlEventWait(input, output, false, ctrl);
|
||||
case 0x1e:
|
||||
return IocCtrlEventWait(input, output, true, ctrl);
|
||||
case 0x1f:
|
||||
return IocCtrlEventRegister(input, output);
|
||||
case 0x20:
|
||||
return IocCtrlEventUnregister(input, output);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocGetConfigParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
|
||||
params.param_str.data());
|
||||
return 0x30006; // Returns error on production mode
|
||||
return NvResult::ConfigVarNotFound; // Returns error on production mode
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
bool is_async, IoctlCtrl& ctrl) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
bool is_async, IoctlCtrl& ctrl) {
|
||||
IocCtrlEventWaitParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
|
||||
@@ -139,7 +154,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocCtrlEventRegisterParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
const u32 event_id = params.user_event_id & 0x00FF;
|
||||
@@ -154,7 +169,8 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
|
||||
std::vector<u8>& output) {
|
||||
IocCtrlEventUnregisterParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
const u32 event_id = params.user_event_id & 0x00FF;
|
||||
@@ -169,7 +185,7 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocCtrlEventSignalParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
|
||||
@@ -18,132 +18,116 @@ public:
|
||||
SyncpointManager& syncpoint_manager);
|
||||
~nvhost_ctrl() override;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocSyncptReadCommand = 0xC0080014,
|
||||
IocSyncptIncrCommand = 0x40040015,
|
||||
IocSyncptWaitCommand = 0xC00C0016,
|
||||
IocModuleMutexCommand = 0x40080017,
|
||||
IocModuleRegRDWRCommand = 0xC0180018,
|
||||
IocSyncptWaitexCommand = 0xC0100019,
|
||||
IocSyncptReadMaxCommand = 0xC008001A,
|
||||
IocGetConfigCommand = 0xC183001B,
|
||||
IocCtrlClearEventWaitCommand = 0xC004001C,
|
||||
IocCtrlEventWaitCommand = 0xC010001D,
|
||||
IocCtrlEventWaitAsyncCommand = 0xC010001E,
|
||||
IocCtrlEventRegisterCommand = 0xC004001F,
|
||||
IocCtrlEventUnregisterCommand = 0xC0040020,
|
||||
IocCtrlEventKillCommand = 0x40080021,
|
||||
};
|
||||
struct IocSyncptReadParams {
|
||||
u32_le id;
|
||||
u32_le value;
|
||||
u32_le id{};
|
||||
u32_le value{};
|
||||
};
|
||||
static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size");
|
||||
|
||||
struct IocSyncptIncrParams {
|
||||
u32_le id;
|
||||
u32_le id{};
|
||||
};
|
||||
static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size");
|
||||
|
||||
struct IocSyncptWaitParams {
|
||||
u32_le id;
|
||||
u32_le thresh;
|
||||
s32_le timeout;
|
||||
u32_le id{};
|
||||
u32_le thresh{};
|
||||
s32_le timeout{};
|
||||
};
|
||||
static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size");
|
||||
|
||||
struct IocModuleMutexParams {
|
||||
u32_le id;
|
||||
u32_le lock; // (0 = unlock and 1 = lock)
|
||||
u32_le id{};
|
||||
u32_le lock{}; // (0 = unlock and 1 = lock)
|
||||
};
|
||||
static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size");
|
||||
|
||||
struct IocModuleRegRDWRParams {
|
||||
u32_le id;
|
||||
u32_le num_offsets;
|
||||
u32_le block_size;
|
||||
u32_le offsets;
|
||||
u32_le values;
|
||||
u32_le write;
|
||||
u32_le id{};
|
||||
u32_le num_offsets{};
|
||||
u32_le block_size{};
|
||||
u32_le offsets{};
|
||||
u32_le values{};
|
||||
u32_le write{};
|
||||
};
|
||||
static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size");
|
||||
|
||||
struct IocSyncptWaitexParams {
|
||||
u32_le id;
|
||||
u32_le thresh;
|
||||
s32_le timeout;
|
||||
u32_le value;
|
||||
u32_le id{};
|
||||
u32_le thresh{};
|
||||
s32_le timeout{};
|
||||
u32_le value{};
|
||||
};
|
||||
static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size");
|
||||
|
||||
struct IocSyncptReadMaxParams {
|
||||
u32_le id;
|
||||
u32_le value;
|
||||
u32_le id{};
|
||||
u32_le value{};
|
||||
};
|
||||
static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size");
|
||||
|
||||
struct IocGetConfigParams {
|
||||
std::array<char, 0x41> domain_str;
|
||||
std::array<char, 0x41> param_str;
|
||||
std::array<char, 0x101> config_str;
|
||||
std::array<char, 0x41> domain_str{};
|
||||
std::array<char, 0x41> param_str{};
|
||||
std::array<char, 0x101> config_str{};
|
||||
};
|
||||
static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventSignalParams {
|
||||
u32_le event_id;
|
||||
u32_le event_id{};
|
||||
};
|
||||
static_assert(sizeof(IocCtrlEventSignalParams) == 4,
|
||||
"IocCtrlEventSignalParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventWaitParams {
|
||||
u32_le syncpt_id;
|
||||
u32_le threshold;
|
||||
s32_le timeout;
|
||||
u32_le value;
|
||||
u32_le syncpt_id{};
|
||||
u32_le threshold{};
|
||||
s32_le timeout{};
|
||||
u32_le value{};
|
||||
};
|
||||
static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventWaitAsyncParams {
|
||||
u32_le syncpt_id;
|
||||
u32_le threshold;
|
||||
u32_le timeout;
|
||||
u32_le value;
|
||||
u32_le syncpt_id{};
|
||||
u32_le threshold{};
|
||||
u32_le timeout{};
|
||||
u32_le value{};
|
||||
};
|
||||
static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16,
|
||||
"IocCtrlEventWaitAsyncParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventRegisterParams {
|
||||
u32_le user_event_id;
|
||||
u32_le user_event_id{};
|
||||
};
|
||||
static_assert(sizeof(IocCtrlEventRegisterParams) == 4,
|
||||
"IocCtrlEventRegisterParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventUnregisterParams {
|
||||
u32_le user_event_id;
|
||||
u32_le user_event_id{};
|
||||
};
|
||||
static_assert(sizeof(IocCtrlEventUnregisterParams) == 4,
|
||||
"IocCtrlEventUnregisterParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventKill {
|
||||
u64_le user_events;
|
||||
u64_le user_events{};
|
||||
};
|
||||
static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size");
|
||||
|
||||
u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async,
|
||||
IoctlCtrl& ctrl);
|
||||
|
||||
u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async,
|
||||
IoctlCtrl& ctrl);
|
||||
NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
EventInterface& events_interface;
|
||||
SyncpointManager& syncpoint_manager;
|
||||
|
||||
@@ -15,39 +15,114 @@ namespace Service::Nvidia::Devices {
|
||||
nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
|
||||
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
|
||||
|
||||
u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& input2, std::vector<u8>& output,
|
||||
std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
||||
command.raw, input.size(), output.size());
|
||||
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocGetCharacteristicsCommand:
|
||||
return GetCharacteristics(input, output, output2, version);
|
||||
case IoctlCommand::IocGetTPCMasksCommand:
|
||||
return GetTPCMasks(input, output, output2, version);
|
||||
case IoctlCommand::IocGetActiveSlotMaskCommand:
|
||||
return GetActiveSlotMask(input, output);
|
||||
case IoctlCommand::IocZcullGetCtxSizeCommand:
|
||||
return ZCullGetCtxSize(input, output);
|
||||
case IoctlCommand::IocZcullGetInfo:
|
||||
return ZCullGetInfo(input, output);
|
||||
case IoctlCommand::IocZbcSetTable:
|
||||
return ZBCSetTable(input, output);
|
||||
case IoctlCommand::IocZbcQueryTable:
|
||||
return ZBCQueryTable(input, output);
|
||||
case IoctlCommand::IocFlushL2:
|
||||
return FlushL2(input, output);
|
||||
case IoctlCommand::IocGetGpuTime:
|
||||
return GetGpuTime(input, output);
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
return 0;
|
||||
NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return ZCullGetCtxSize(input, output);
|
||||
case 0x2:
|
||||
return ZCullGetInfo(input, output);
|
||||
case 0x3:
|
||||
return ZBCSetTable(input, output);
|
||||
case 0x4:
|
||||
return ZBCQueryTable(input, output);
|
||||
case 0x5:
|
||||
return GetCharacteristics(input, output);
|
||||
case 0x6:
|
||||
return GetTPCMasks(input, output);
|
||||
case 0x7:
|
||||
return FlushL2(input, output);
|
||||
case 0x14:
|
||||
return GetActiveSlotMask(input, output);
|
||||
case 0x1c:
|
||||
return GetGpuTime(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& output2, IoctlVersion version) {
|
||||
NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output,
|
||||
IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
case 0x5:
|
||||
return GetCharacteristics(input, output, inline_output);
|
||||
case 0x6:
|
||||
return GetTPCMasks(input, output, inline_output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
|
||||
std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlCharacteristics params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.gc.arch = 0x120;
|
||||
params.gc.impl = 0xb;
|
||||
params.gc.rev = 0xa1;
|
||||
params.gc.num_gpc = 0x1;
|
||||
params.gc.l2_cache_size = 0x40000;
|
||||
params.gc.on_board_video_memory_size = 0x0;
|
||||
params.gc.num_tpc_per_gpc = 0x2;
|
||||
params.gc.bus_type = 0x20;
|
||||
params.gc.big_page_size = 0x20000;
|
||||
params.gc.compression_page_size = 0x20000;
|
||||
params.gc.pde_coverage_bit_count = 0x1B;
|
||||
params.gc.available_big_page_sizes = 0x30000;
|
||||
params.gc.gpc_mask = 0x1;
|
||||
params.gc.sm_arch_sm_version = 0x503;
|
||||
params.gc.sm_arch_spa_version = 0x503;
|
||||
params.gc.sm_arch_warp_count = 0x80;
|
||||
params.gc.gpu_va_bit_count = 0x28;
|
||||
params.gc.reserved = 0x0;
|
||||
params.gc.flags = 0x55;
|
||||
params.gc.twod_class = 0x902D;
|
||||
params.gc.threed_class = 0xB197;
|
||||
params.gc.compute_class = 0xB1C0;
|
||||
params.gc.gpfifo_class = 0xB06F;
|
||||
params.gc.inline_to_memory_class = 0xA140;
|
||||
params.gc.dma_copy_class = 0xB0B5;
|
||||
params.gc.max_fbps_count = 0x1;
|
||||
params.gc.fbp_en_mask = 0x0;
|
||||
params.gc.max_ltc_per_fbp = 0x2;
|
||||
params.gc.max_lts_per_ltc = 0x1;
|
||||
params.gc.max_tex_per_tpc = 0x0;
|
||||
params.gc.max_gpc_count = 0x1;
|
||||
params.gc.rop_l2_en_mask_0 = 0x21D70;
|
||||
params.gc.rop_l2_en_mask_1 = 0x0;
|
||||
params.gc.chipname = 0x6230326D67;
|
||||
params.gc.gr_compbit_store_base_hw = 0x0;
|
||||
params.gpu_characteristics_buf_size = 0xA0;
|
||||
params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlCharacteristics params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
@@ -89,35 +164,36 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto
|
||||
params.gpu_characteristics_buf_size = 0xA0;
|
||||
params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
|
||||
|
||||
if (version == IoctlVersion::Version3) {
|
||||
std::memcpy(output.data(), input.data(), output.size());
|
||||
std::memcpy(output2.data(), ¶ms.gc, output2.size());
|
||||
} else {
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
}
|
||||
return 0;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& output2, IoctlVersion version) {
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlGpuGetTpcMasksArgs params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
|
||||
if (params.mask_buffer_size != 0) {
|
||||
params.tcp_mask = 3;
|
||||
}
|
||||
|
||||
if (version == IoctlVersion::Version3) {
|
||||
std::memcpy(output.data(), input.data(), output.size());
|
||||
std::memcpy(output2.data(), ¶ms.tcp_mask, output2.size());
|
||||
} else {
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
}
|
||||
|
||||
return 0;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) {
|
||||
IoctlGpuGetTpcMasksArgs params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
|
||||
if (params.mask_buffer_size != 0) {
|
||||
params.tcp_mask = 3;
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
std::memcpy(inline_output.data(), ¶ms.tcp_mask, inline_output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlActiveSlotMask params{};
|
||||
@@ -127,10 +203,10 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
|
||||
params.slot = 0x07;
|
||||
params.mask = 0x01;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlZcullGetCtxSize params{};
|
||||
@@ -139,10 +215,10 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
|
||||
}
|
||||
params.size = 0x1;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlNvgpuGpuZcullGetInfoArgs params{};
|
||||
@@ -162,47 +238,47 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&
|
||||
params.subregion_height_align_pixels = 0x40;
|
||||
params.subregion_count = 0x10;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcSetTable params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO(ogniK): What does this even actually do?
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcQueryTable params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO : To implement properly
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlFlushL2 params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO : To implement properly
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlGetGpuTime params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -16,32 +16,15 @@ public:
|
||||
explicit nvhost_ctrl_gpu(Core::System& system);
|
||||
~nvhost_ctrl_gpu() override;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocGetCharacteristicsCommand = 0xC0B04705,
|
||||
IocGetTPCMasksCommand = 0xC0184706,
|
||||
IocGetActiveSlotMaskCommand = 0x80084714,
|
||||
IocZcullGetCtxSizeCommand = 0x80044701,
|
||||
IocZcullGetInfo = 0x80284702,
|
||||
IocZbcSetTable = 0x402C4703,
|
||||
IocZbcQueryTable = 0xC0344704,
|
||||
IocFlushL2 = 0x40084707,
|
||||
IocInvalICache = 0x4008470D,
|
||||
IocSetMmudebugMode = 0x4008470E,
|
||||
IocSetSmDebugMode = 0x4010470F,
|
||||
IocWaitForPause = 0xC0084710,
|
||||
IocGetTcpExceptionEnStatus = 0x80084711,
|
||||
IocNumVsms = 0x80084712,
|
||||
IocVsmsMapping = 0xC0044713,
|
||||
IocGetErrorChannelUserData = 0xC008471B,
|
||||
IocGetGpuTime = 0xC010471C,
|
||||
IocGetCpuTimeCorrelationInfo = 0xC108471D,
|
||||
};
|
||||
|
||||
struct IoctlGpuCharacteristics {
|
||||
u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200)
|
||||
u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B)
|
||||
@@ -159,17 +142,21 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
|
||||
|
||||
u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& output2, IoctlVersion version);
|
||||
u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, std::vector<u8>& output2,
|
||||
IoctlVersion version);
|
||||
u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output);
|
||||
|
||||
NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output);
|
||||
|
||||
NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -23,107 +23,134 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
|
||||
|
||||
nvhost_gpu::~nvhost_gpu() = default;
|
||||
|
||||
u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
||||
command.raw, input.size(), output.size());
|
||||
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
||||
return SetNVMAPfd(input, output);
|
||||
case IoctlCommand::IocSetClientDataCommand:
|
||||
return SetClientData(input, output);
|
||||
case IoctlCommand::IocGetClientDataCommand:
|
||||
return GetClientData(input, output);
|
||||
case IoctlCommand::IocZCullBind:
|
||||
return ZCullBind(input, output);
|
||||
case IoctlCommand::IocSetErrorNotifierCommand:
|
||||
return SetErrorNotifier(input, output);
|
||||
case IoctlCommand::IocChannelSetPriorityCommand:
|
||||
return SetChannelPriority(input, output);
|
||||
case IoctlCommand::IocAllocGPFIFOEx2Command:
|
||||
return AllocGPFIFOEx2(input, output);
|
||||
case IoctlCommand::IocAllocObjCtxCommand:
|
||||
return AllocateObjectContext(input, output);
|
||||
case IoctlCommand::IocChannelGetWaitbaseCommand:
|
||||
return GetWaitbase(input, output);
|
||||
case IoctlCommand::IocChannelSetTimeoutCommand:
|
||||
return ChannelSetTimeout(input, output);
|
||||
case IoctlCommand::IocChannelSetTimeslice:
|
||||
return ChannelSetTimeslice(input, output);
|
||||
default:
|
||||
NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
case 0x3:
|
||||
return GetWaitbase(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return SetNVMAPfd(input, output);
|
||||
case 0x3:
|
||||
return ChannelSetTimeout(input, output);
|
||||
case 0x8:
|
||||
return SubmitGPFIFOBase(input, output, false);
|
||||
case 0x9:
|
||||
return AllocateObjectContext(input, output);
|
||||
case 0xb:
|
||||
return ZCullBind(input, output);
|
||||
case 0xc:
|
||||
return SetErrorNotifier(input, output);
|
||||
case 0xd:
|
||||
return SetChannelPriority(input, output);
|
||||
case 0x1a:
|
||||
return AllocGPFIFOEx2(input, output);
|
||||
case 0x1b:
|
||||
return SubmitGPFIFOBase(input, output, true);
|
||||
case 0x1d:
|
||||
return ChannelSetTimeslice(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
case 0x14:
|
||||
return SetClientData(input, output);
|
||||
case 0x15:
|
||||
return GetClientData(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (command.group == NVGPU_IOCTL_MAGIC) {
|
||||
if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) {
|
||||
return SubmitGPFIFO(input, output);
|
||||
}
|
||||
if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) {
|
||||
return KickoffPB(input, output, input2, version);
|
||||
}
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
return 0;
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
};
|
||||
|
||||
u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1b:
|
||||
return SubmitGPFIFOBase(input, inline_input, output);
|
||||
}
|
||||
break;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
user_data = params.data;
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.data = user_data;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
std::memcpy(&zcull_params, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
|
||||
zcull_params.mode);
|
||||
|
||||
std::memcpy(output.data(), &zcull_params, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSetErrorNotifier params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
|
||||
params.size, params.mem);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
std::memcpy(&channel_priority, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
|
||||
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlAllocGpfifoEx2 params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV,
|
||||
@@ -137,10 +164,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
params.fence_out = channel_fence;
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlAllocObjCtx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
|
||||
@@ -148,7 +175,7 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
|
||||
|
||||
params.obj_id = 0x0;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
|
||||
@@ -192,8 +219,8 @@ static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
||||
Tegra::CommandList&& entries) {
|
||||
NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
||||
Tegra::CommandList&& entries) {
|
||||
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
|
||||
params.num_entries, params.flags.raw);
|
||||
|
||||
@@ -227,69 +254,70 @@ u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& out
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo));
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
bool kickoff) {
|
||||
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||
UNIMPLEMENTED();
|
||||
return NvResult::InvalidSize;
|
||||
}
|
||||
IoctlSubmitGpfifo params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
||||
|
||||
Tegra::CommandList entries(params.num_entries);
|
||||
std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
|
||||
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
const std::vector<u8>& input2, IoctlVersion version) {
|
||||
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
IoctlSubmitGpfifo params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
||||
|
||||
Tegra::CommandList entries(params.num_entries);
|
||||
if (version == IoctlVersion::Version2) {
|
||||
std::memcpy(entries.command_lists.data(), input2.data(),
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
} else {
|
||||
if (kickoff) {
|
||||
system.Memory().ReadBlock(params.address, entries.command_lists.data(),
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
} else {
|
||||
std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
}
|
||||
|
||||
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input,
|
||||
const std::vector<u8>& input_inline,
|
||||
std::vector<u8>& output) {
|
||||
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||
UNIMPLEMENTED();
|
||||
return NvResult::InvalidSize;
|
||||
}
|
||||
IoctlSubmitGpfifo params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
||||
Tegra::CommandList entries(params.num_entries);
|
||||
std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size());
|
||||
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlGetWaitbase params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlChannelSetTimeout params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));
|
||||
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
|
||||
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSetTimeslice params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice));
|
||||
LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
|
||||
|
||||
channel_timeslice = params.timeslice;
|
||||
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -20,43 +20,21 @@ class SyncpointManager;
|
||||
namespace Service::Nvidia::Devices {
|
||||
|
||||
class nvmap;
|
||||
constexpr u32 NVGPU_IOCTL_MAGIC('H');
|
||||
constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8);
|
||||
constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
|
||||
|
||||
class nvhost_gpu final : public nvdevice {
|
||||
public:
|
||||
explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
|
||||
SyncpointManager& syncpoint_manager);
|
||||
~nvhost_gpu() override;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocSetNVMAPfdCommand = 0x40044801,
|
||||
IocAllocGPFIFOCommand = 0x40084805,
|
||||
IocSetClientDataCommand = 0x40084714,
|
||||
IocGetClientDataCommand = 0x80084715,
|
||||
IocZCullBind = 0xc010480b,
|
||||
IocSetErrorNotifierCommand = 0xC018480C,
|
||||
IocChannelSetPriorityCommand = 0x4004480D,
|
||||
IocEnableCommand = 0x0000480E,
|
||||
IocDisableCommand = 0x0000480F,
|
||||
IocPreemptCommand = 0x00004810,
|
||||
IocForceResetCommand = 0x00004811,
|
||||
IocEventIdControlCommand = 0x40084812,
|
||||
IocGetErrorNotificationCommand = 0xC0104817,
|
||||
IocAllocGPFIFOExCommand = 0x40204818,
|
||||
IocAllocGPFIFOEx2Command = 0xC020481A,
|
||||
IocAllocObjCtxCommand = 0xC0104809,
|
||||
IocChannelGetWaitbaseCommand = 0xC0080003,
|
||||
IocChannelSetTimeoutCommand = 0x40044803,
|
||||
IocChannelSetTimeslice = 0xC004481D,
|
||||
};
|
||||
|
||||
enum class CtxObjects : u32_le {
|
||||
Ctx2D = 0x902D,
|
||||
Ctx3D = 0xB197,
|
||||
@@ -67,63 +45,63 @@ private:
|
||||
};
|
||||
|
||||
struct IoctlSetNvmapFD {
|
||||
u32_le nvmap_fd;
|
||||
s32_le nvmap_fd{};
|
||||
};
|
||||
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
||||
|
||||
struct IoctlChannelSetTimeout {
|
||||
u32_le timeout;
|
||||
u32_le timeout{};
|
||||
};
|
||||
static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size");
|
||||
|
||||
struct IoctlAllocGPFIFO {
|
||||
u32_le num_entries;
|
||||
u32_le flags;
|
||||
u32_le num_entries{};
|
||||
u32_le flags{};
|
||||
};
|
||||
static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size");
|
||||
|
||||
struct IoctlClientData {
|
||||
u64_le data;
|
||||
u64_le data{};
|
||||
};
|
||||
static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size");
|
||||
|
||||
struct IoctlZCullBind {
|
||||
u64_le gpu_va;
|
||||
u32_le mode; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf
|
||||
u64_le gpu_va{};
|
||||
u32_le mode{}; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf
|
||||
INSERT_PADDING_WORDS(1);
|
||||
};
|
||||
static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size");
|
||||
|
||||
struct IoctlSetErrorNotifier {
|
||||
u64_le offset;
|
||||
u64_le size;
|
||||
u32_le mem; // nvmap object handle
|
||||
u64_le offset{};
|
||||
u64_le size{};
|
||||
u32_le mem{}; // nvmap object handle
|
||||
INSERT_PADDING_WORDS(1);
|
||||
};
|
||||
static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size");
|
||||
|
||||
struct IoctlChannelSetPriority {
|
||||
u32_le priority;
|
||||
u32_le priority{};
|
||||
};
|
||||
static_assert(sizeof(IoctlChannelSetPriority) == 4,
|
||||
"IoctlChannelSetPriority is incorrect size");
|
||||
|
||||
struct IoctlSetTimeslice {
|
||||
u32_le timeslice;
|
||||
u32_le timeslice{};
|
||||
};
|
||||
static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size");
|
||||
|
||||
struct IoctlEventIdControl {
|
||||
u32_le cmd; // 0=disable, 1=enable, 2=clear
|
||||
u32_le id;
|
||||
u32_le cmd{}; // 0=disable, 1=enable, 2=clear
|
||||
u32_le id{};
|
||||
};
|
||||
static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size");
|
||||
|
||||
struct IoctlGetErrorNotification {
|
||||
u64_le timestamp;
|
||||
u32_le info32;
|
||||
u16_le info16;
|
||||
u16_le status; // always 0xFFFF
|
||||
u64_le timestamp{};
|
||||
u32_le info32{};
|
||||
u16_le info16{};
|
||||
u16_le status{}; // always 0xFFFF
|
||||
};
|
||||
static_assert(sizeof(IoctlGetErrorNotification) == 16,
|
||||
"IoctlGetErrorNotification is incorrect size");
|
||||
@@ -131,39 +109,39 @@ private:
|
||||
static_assert(sizeof(Fence) == 8, "Fence is incorrect size");
|
||||
|
||||
struct IoctlAllocGpfifoEx {
|
||||
u32_le num_entries;
|
||||
u32_le flags;
|
||||
u32_le unk0;
|
||||
u32_le unk1;
|
||||
u32_le unk2;
|
||||
u32_le unk3;
|
||||
u32_le unk4;
|
||||
u32_le unk5;
|
||||
u32_le num_entries{};
|
||||
u32_le flags{};
|
||||
u32_le unk0{};
|
||||
u32_le unk1{};
|
||||
u32_le unk2{};
|
||||
u32_le unk3{};
|
||||
u32_le unk4{};
|
||||
u32_le unk5{};
|
||||
};
|
||||
static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");
|
||||
|
||||
struct IoctlAllocGpfifoEx2 {
|
||||
u32_le num_entries; // in
|
||||
u32_le flags; // in
|
||||
u32_le unk0; // in (1 works)
|
||||
Fence fence_out; // out
|
||||
u32_le unk1; // in
|
||||
u32_le unk2; // in
|
||||
u32_le unk3; // in
|
||||
u32_le num_entries{}; // in
|
||||
u32_le flags{}; // in
|
||||
u32_le unk0{}; // in (1 works)
|
||||
Fence fence_out{}; // out
|
||||
u32_le unk1{}; // in
|
||||
u32_le unk2{}; // in
|
||||
u32_le unk3{}; // in
|
||||
};
|
||||
static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size");
|
||||
|
||||
struct IoctlAllocObjCtx {
|
||||
u32_le class_num; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA,
|
||||
// 0xB06F=channel_gpfifo
|
||||
u32_le flags;
|
||||
u64_le obj_id; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported
|
||||
u32_le class_num{}; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA,
|
||||
// 0xB06F=channel_gpfifo
|
||||
u32_le flags{};
|
||||
u64_le obj_id{}; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported
|
||||
};
|
||||
static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size");
|
||||
|
||||
struct IoctlSubmitGpfifo {
|
||||
u64_le address; // pointer to gpfifo entry structs
|
||||
u32_le num_entries; // number of fence objects being submitted
|
||||
u64_le address{}; // pointer to gpfifo entry structs
|
||||
u32_le num_entries{}; // number of fence objects being submitted
|
||||
union {
|
||||
u32_le raw;
|
||||
BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list
|
||||
@@ -172,7 +150,7 @@ private:
|
||||
BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt
|
||||
BitField<8, 1, u32_le> increment; // increment the returned fence
|
||||
} flags;
|
||||
Fence fence_out; // returned new fence object for others to wait on
|
||||
Fence fence_out{}; // returned new fence object for others to wait on
|
||||
|
||||
u32 AddIncrementValue() const {
|
||||
return flags.add_increment.Value() << 1;
|
||||
@@ -182,33 +160,34 @@ private:
|
||||
"IoctlSubmitGpfifo is incorrect size");
|
||||
|
||||
struct IoctlGetWaitbase {
|
||||
u32 unknown; // seems to be ignored? Nintendo added this
|
||||
u32 value;
|
||||
u32 unknown{}; // seems to be ignored? Nintendo added this
|
||||
u32 value{};
|
||||
};
|
||||
static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size");
|
||||
|
||||
u32_le nvmap_fd{};
|
||||
s32_le nvmap_fd{};
|
||||
u64_le user_data{};
|
||||
IoctlZCullBind zcull_params{};
|
||||
u32_le channel_priority{};
|
||||
u32_le channel_timeslice{};
|
||||
|
||||
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetClientData(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 ZCullBind(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
||||
Tegra::CommandList&& entries);
|
||||
u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
const std::vector<u8>& input2, IoctlVersion version);
|
||||
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
||||
Tegra::CommandList&& entries);
|
||||
NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
bool kickoff = false);
|
||||
NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline,
|
||||
std::vector<u8>& output);
|
||||
NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
std::shared_ptr<nvmap> nvmap_dev;
|
||||
SyncpointManager& syncpoint_manager;
|
||||
|
||||
@@ -15,46 +15,59 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de
|
||||
: nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
|
||||
nvhost_nvdec::~nvhost_nvdec() = default;
|
||||
|
||||
u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
||||
command.raw, input.size(), output.size());
|
||||
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
||||
return SetNVMAPfd(input);
|
||||
case IoctlCommand::IocSubmit:
|
||||
return Submit(input, output);
|
||||
case IoctlCommand::IocGetSyncpoint:
|
||||
return GetSyncpoint(input, output);
|
||||
case IoctlCommand::IocGetWaitbase:
|
||||
return GetWaitbase(input, output);
|
||||
case IoctlCommand::IocMapBuffer:
|
||||
case IoctlCommand::IocMapBuffer2:
|
||||
case IoctlCommand::IocMapBuffer3:
|
||||
case IoctlCommand::IocMapBufferEx:
|
||||
return MapBuffer(input, output);
|
||||
case IoctlCommand::IocUnmapBufferEx: {
|
||||
// This command is sent when the video stream has ended, flush all video contexts
|
||||
// This is usually sent in the folowing order: vic, nvdec, vic.
|
||||
// Inform the GPU to clear any remaining nvdec buffers when this is detected.
|
||||
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
|
||||
Tegra::ChCommandHeaderList cmdlist(1);
|
||||
cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
|
||||
system.GPU().PushCommandBuffer(cmdlist);
|
||||
[[fallthrough]]; // fallthrough to unmap buffers
|
||||
};
|
||||
case IoctlCommand::IocUnmapBuffer:
|
||||
case IoctlCommand::IocUnmapBuffer2:
|
||||
case IoctlCommand::IocUnmapBuffer3:
|
||||
return UnmapBuffer(input, output);
|
||||
case IoctlCommand::IocSetSubmitTimeout:
|
||||
return SetSubmitTimeout(input, output);
|
||||
NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return Submit(input, output);
|
||||
case 0x2:
|
||||
return GetSyncpoint(input, output);
|
||||
case 0x3:
|
||||
return GetWaitbase(input, output);
|
||||
case 0x7:
|
||||
return SetSubmitTimeout(input, output);
|
||||
case 0x9:
|
||||
return MapBuffer(input, output);
|
||||
case 0xa: {
|
||||
if (command.length == 0x1c) {
|
||||
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
|
||||
Tegra::ChCommandHeaderList cmdlist(1);
|
||||
cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
|
||||
system.GPU().PushCommandBuffer(cmdlist);
|
||||
}
|
||||
return UnmapBuffer(input, output);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return SetNVMAPfd(input);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
|
||||
return 0;
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -14,26 +14,13 @@ public:
|
||||
explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvhost_nvdec() override;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) override;
|
||||
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocSetNVMAPfdCommand = 0x40044801,
|
||||
IocSubmit = 0xC0400001,
|
||||
IocGetSyncpoint = 0xC0080002,
|
||||
IocGetWaitbase = 0xC0080003,
|
||||
IocMapBuffer = 0xC01C0009,
|
||||
IocMapBuffer2 = 0xC16C0009,
|
||||
IocMapBuffer3 = 0xC15C0009,
|
||||
IocMapBufferEx = 0xC0A40009,
|
||||
IocUnmapBuffer = 0xC0A4000A,
|
||||
IocUnmapBuffer2 = 0xC16C000A,
|
||||
IocUnmapBufferEx = 0xC01C000A,
|
||||
IocUnmapBuffer3 = 0xC15C000A,
|
||||
IocSetSubmitTimeout = 0x40040007,
|
||||
};
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -36,26 +36,20 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace NvErrCodes {
|
||||
constexpr u32 Success{};
|
||||
[[maybe_unused]] constexpr u32 OutOfMemory{static_cast<u32>(-12)};
|
||||
constexpr u32 InvalidInput{static_cast<u32>(-22)};
|
||||
} // namespace NvErrCodes
|
||||
|
||||
nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
|
||||
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
||||
nvhost_nvdec_common::~nvhost_nvdec_common() = default;
|
||||
|
||||
u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
|
||||
NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD));
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSubmit params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));
|
||||
LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
|
||||
@@ -83,12 +77,12 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o
|
||||
|
||||
for (const auto& cmd_buffer : command_buffers) {
|
||||
auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
|
||||
ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;);
|
||||
ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
|
||||
const auto map = FindBufferMap(object->dma_map_addr);
|
||||
if (!map) {
|
||||
LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",
|
||||
object->addr, object->dma_map_addr);
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
|
||||
gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(),
|
||||
@@ -105,10 +99,10 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o
|
||||
offset = WriteVectors(output, syncpt_increments, offset);
|
||||
offset = WriteVectors(output, wait_checks, offset);
|
||||
|
||||
return NvErrCodes::Success;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlGetSyncpoint params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));
|
||||
LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
|
||||
@@ -118,18 +112,18 @@ u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<
|
||||
params.value = 0;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint));
|
||||
|
||||
return NvErrCodes::Success;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlGetWaitbase params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase));
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||
@@ -143,7 +137,7 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>
|
||||
if (!object) {
|
||||
LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvErrCodes::InvalidInput;
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
if (object->dma_map_addr == 0) {
|
||||
// NVDEC and VIC memory is in the 32-bit address space
|
||||
@@ -165,10 +159,10 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>
|
||||
std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
|
||||
cmd_buffer_handles.size() * sizeof(MapBufferEntry));
|
||||
|
||||
return NvErrCodes::Success;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||
@@ -181,7 +175,7 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u
|
||||
if (!object) {
|
||||
LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvErrCodes::InvalidInput;
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
|
||||
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
|
||||
@@ -193,13 +187,14 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u
|
||||
object->dma_map_addr = 0;
|
||||
}
|
||||
std::memset(output.data(), 0, output.size());
|
||||
return NvErrCodes::Success;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input,
|
||||
std::vector<u8>& output) {
|
||||
std::memcpy(&submit_timeout, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
return NvErrCodes::Success;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
|
||||
|
||||
@@ -18,9 +18,38 @@ public:
|
||||
explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvhost_nvdec_common() override;
|
||||
|
||||
virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) = 0;
|
||||
/**
|
||||
* Handles an ioctl1 request.
|
||||
* @param command The ioctl command id.
|
||||
* @param input A buffer containing the input data for the ioctl.
|
||||
* @param output A buffer where the output data will be written to.
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) = 0;
|
||||
|
||||
/**
|
||||
* Handles an ioctl2 request.
|
||||
* @param command The ioctl command id.
|
||||
* @param input A buffer containing the input data for the ioctl.
|
||||
* @param inline_input A buffer containing the input data for the ioctl which has been inlined.
|
||||
* @param output A buffer where the output data will be written to.
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) = 0;
|
||||
|
||||
/**
|
||||
* Handles an ioctl3 request.
|
||||
* @param command The ioctl command id.
|
||||
* @param input A buffer containing the input data for the ioctl.
|
||||
* @param output A buffer where the output data will be written to.
|
||||
* @param inline_output A buffer where the inlined output data will be written to.
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) = 0;
|
||||
|
||||
protected:
|
||||
class BufferMap final {
|
||||
@@ -63,102 +92,102 @@ protected:
|
||||
};
|
||||
|
||||
struct IoctlSetNvmapFD {
|
||||
u32_le nvmap_fd;
|
||||
s32_le nvmap_fd{};
|
||||
};
|
||||
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
||||
|
||||
struct IoctlSubmitCommandBuffer {
|
||||
u32_le id;
|
||||
u32_le offset;
|
||||
u32_le count;
|
||||
u32_le id{};
|
||||
u32_le offset{};
|
||||
u32_le count{};
|
||||
};
|
||||
static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
|
||||
"IoctlSubmitCommandBuffer is incorrect size");
|
||||
struct IoctlSubmit {
|
||||
u32_le cmd_buffer_count;
|
||||
u32_le relocation_count;
|
||||
u32_le syncpoint_count;
|
||||
u32_le fence_count;
|
||||
u32_le cmd_buffer_count{};
|
||||
u32_le relocation_count{};
|
||||
u32_le syncpoint_count{};
|
||||
u32_le fence_count{};
|
||||
};
|
||||
static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");
|
||||
|
||||
struct CommandBuffer {
|
||||
s32 memory_id;
|
||||
u32 offset;
|
||||
s32 word_count;
|
||||
s32 memory_id{};
|
||||
u32 offset{};
|
||||
s32 word_count{};
|
||||
};
|
||||
static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");
|
||||
|
||||
struct Reloc {
|
||||
s32 cmdbuffer_memory;
|
||||
s32 cmdbuffer_offset;
|
||||
s32 target;
|
||||
s32 target_offset;
|
||||
s32 cmdbuffer_memory{};
|
||||
s32 cmdbuffer_offset{};
|
||||
s32 target{};
|
||||
s32 target_offset{};
|
||||
};
|
||||
static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
|
||||
|
||||
struct SyncptIncr {
|
||||
u32 id;
|
||||
u32 increments;
|
||||
u32 id{};
|
||||
u32 increments{};
|
||||
};
|
||||
static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
|
||||
|
||||
struct Fence {
|
||||
u32 id;
|
||||
u32 value;
|
||||
u32 id{};
|
||||
u32 value{};
|
||||
};
|
||||
static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
|
||||
|
||||
struct IoctlGetSyncpoint {
|
||||
// Input
|
||||
u32_le param;
|
||||
u32_le param{};
|
||||
// Output
|
||||
u32_le value;
|
||||
u32_le value{};
|
||||
};
|
||||
static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");
|
||||
|
||||
struct IoctlGetWaitbase {
|
||||
u32_le unknown; // seems to be ignored? Nintendo added this
|
||||
u32_le value;
|
||||
u32_le unknown{}; // seems to be ignored? Nintendo added this
|
||||
u32_le value{};
|
||||
};
|
||||
static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
|
||||
|
||||
struct IoctlMapBuffer {
|
||||
u32_le num_entries;
|
||||
u32_le data_address; // Ignored by the driver.
|
||||
u32_le attach_host_ch_das;
|
||||
u32_le num_entries{};
|
||||
u32_le data_address{}; // Ignored by the driver.
|
||||
u32_le attach_host_ch_das{};
|
||||
};
|
||||
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
|
||||
|
||||
struct IocGetIdParams {
|
||||
// Input
|
||||
u32_le param;
|
||||
u32_le param{};
|
||||
// Output
|
||||
u32_le value;
|
||||
u32_le value{};
|
||||
};
|
||||
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
|
||||
|
||||
// Used for mapping and unmapping command buffers
|
||||
struct MapBufferEntry {
|
||||
u32_le map_handle;
|
||||
u32_le map_address;
|
||||
u32_le map_handle{};
|
||||
u32_le map_address{};
|
||||
};
|
||||
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
|
||||
|
||||
/// Ioctl command implementations
|
||||
u32 SetNVMAPfd(const std::vector<u8>& input);
|
||||
u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult SetNVMAPfd(const std::vector<u8>& input);
|
||||
NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
|
||||
void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
|
||||
std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
|
||||
|
||||
u32_le nvmap_fd{};
|
||||
s32_le nvmap_fd{};
|
||||
u32_le submit_timeout{};
|
||||
std::shared_ptr<nvmap> nvmap_dev;
|
||||
|
||||
|
||||
@@ -13,28 +13,45 @@ namespace Service::Nvidia::Devices {
|
||||
nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
|
||||
nvhost_nvjpg::~nvhost_nvjpg() = default;
|
||||
|
||||
u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
||||
command.raw, input.size(), output.size());
|
||||
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
||||
return SetNVMAPfd(input, output);
|
||||
NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return SetNVMAPfd(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
return 0;
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -16,23 +16,23 @@ public:
|
||||
explicit nvhost_nvjpg(Core::System& system);
|
||||
~nvhost_nvjpg() override;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) override;
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocSetNVMAPfdCommand = 0x40044801,
|
||||
};
|
||||
|
||||
struct IoctlSetNvmapFD {
|
||||
u32_le nvmap_fd;
|
||||
s32_le nvmap_fd{};
|
||||
};
|
||||
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
||||
|
||||
u32_le nvmap_fd{};
|
||||
s32_le nvmap_fd{};
|
||||
|
||||
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -15,36 +15,52 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
|
||||
|
||||
nvhost_vic::~nvhost_vic() = default;
|
||||
|
||||
u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
||||
command.raw, input.size(), output.size());
|
||||
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
||||
return SetNVMAPfd(input);
|
||||
case IoctlCommand::IocSubmit:
|
||||
return Submit(input, output);
|
||||
case IoctlCommand::IocGetSyncpoint:
|
||||
return GetSyncpoint(input, output);
|
||||
case IoctlCommand::IocGetWaitbase:
|
||||
return GetWaitbase(input, output);
|
||||
case IoctlCommand::IocMapBuffer:
|
||||
case IoctlCommand::IocMapBuffer2:
|
||||
case IoctlCommand::IocMapBuffer3:
|
||||
case IoctlCommand::IocMapBuffer4:
|
||||
case IoctlCommand::IocMapBufferEx:
|
||||
return MapBuffer(input, output);
|
||||
case IoctlCommand::IocUnmapBuffer:
|
||||
case IoctlCommand::IocUnmapBuffer2:
|
||||
case IoctlCommand::IocUnmapBuffer3:
|
||||
case IoctlCommand::IocUnmapBufferEx:
|
||||
return UnmapBuffer(input, output);
|
||||
NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return Submit(input, output);
|
||||
case 0x2:
|
||||
return GetSyncpoint(input, output);
|
||||
case 0x3:
|
||||
return GetWaitbase(input, output);
|
||||
case 0x9:
|
||||
return MapBuffer(input, output);
|
||||
case 0xa:
|
||||
return UnmapBuffer(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return SetNVMAPfd(input);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
|
||||
return 0;
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -13,25 +13,13 @@ class nvhost_vic final : public nvhost_nvdec_common {
|
||||
public:
|
||||
explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvhost_vic();
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) override;
|
||||
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocSetNVMAPfdCommand = 0x40044801,
|
||||
IocSubmit = 0xC0400001,
|
||||
IocGetSyncpoint = 0xC0080002,
|
||||
IocGetWaitbase = 0xC0080003,
|
||||
IocMapBuffer = 0xC01C0009,
|
||||
IocMapBuffer2 = 0xC0340009,
|
||||
IocMapBuffer3 = 0xC0140009,
|
||||
IocMapBuffer4 = 0xC00C0009,
|
||||
IocMapBufferEx = 0xC03C0009,
|
||||
IocUnmapBuffer = 0xC03C000A,
|
||||
IocUnmapBuffer2 = 0xC034000A,
|
||||
IocUnmapBuffer3 = 0xC00C000A,
|
||||
IocUnmapBufferEx = 0xC01C000A,
|
||||
};
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
};
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -11,13 +11,6 @@
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
|
||||
namespace NvErrCodes {
|
||||
enum {
|
||||
OperationNotPermitted = -1,
|
||||
InvalidValue = -22,
|
||||
};
|
||||
}
|
||||
|
||||
nvmap::nvmap(Core::System& system) : nvdevice(system) {
|
||||
// Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
|
||||
// represent this.
|
||||
@@ -26,6 +19,48 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) {
|
||||
|
||||
nvmap::~nvmap() = default;
|
||||
|
||||
NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
switch (command.group) {
|
||||
case 0x1:
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return IocCreate(input, output);
|
||||
case 0x3:
|
||||
return IocFromId(input, output);
|
||||
case 0x4:
|
||||
return IocAlloc(input, output);
|
||||
case 0x5:
|
||||
return IocFree(input, output);
|
||||
case 0x9:
|
||||
return IocParam(input, output);
|
||||
case 0xe:
|
||||
return IocGetId(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
VAddr nvmap::GetObjectAddress(u32 handle) const {
|
||||
auto object = GetObject(handle);
|
||||
ASSERT(object);
|
||||
@@ -33,28 +68,6 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {
|
||||
return object->addr;
|
||||
}
|
||||
|
||||
u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) {
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::Create:
|
||||
return IocCreate(input, output);
|
||||
case IoctlCommand::Alloc:
|
||||
return IocAlloc(input, output);
|
||||
case IoctlCommand::GetId:
|
||||
return IocGetId(input, output);
|
||||
case IoctlCommand::FromId:
|
||||
return IocFromId(input, output);
|
||||
case IoctlCommand::Param:
|
||||
return IocParam(input, output);
|
||||
case IoctlCommand::Free:
|
||||
return IocFree(input, output);
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvmap::CreateObject(u32 size) {
|
||||
// Create a new nvmap object and obtain a handle to it.
|
||||
auto object = std::make_shared<Object>();
|
||||
@@ -70,35 +83,35 @@ u32 nvmap::CreateObject(u32 size) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocCreateParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
|
||||
|
||||
if (!params.size) {
|
||||
LOG_ERROR(Service_NVDRV, "Size is 0");
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
params.handle = CreateObject(params.size);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocAllocParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
|
||||
|
||||
if (!params.handle) {
|
||||
LOG_ERROR(Service_NVDRV, "Handle is 0");
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
if ((params.align - 1) & params.align) {
|
||||
LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
const u32 min_alignment = 0x1000;
|
||||
@@ -109,12 +122,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
auto object = GetObject(params.handle);
|
||||
if (!object) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
if (object->status == Object::Status::Allocated) {
|
||||
LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
|
||||
return NvResult::InsufficientMemory;
|
||||
}
|
||||
|
||||
object->flags = params.flags;
|
||||
@@ -124,10 +137,10 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
object->status = Object::Status::Allocated;
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocGetIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
@@ -135,22 +148,22 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
|
||||
if (!params.handle) {
|
||||
LOG_ERROR(Service_NVDRV, "Handle is zero");
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
auto object = GetObject(params.handle);
|
||||
if (!object) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
params.id = object->id;
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocFromIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
@@ -160,13 +173,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
[&](const auto& entry) { return entry.second->id == params.id; });
|
||||
if (itr == handles.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
auto& object = itr->second;
|
||||
if (object->status != Object::Status::Allocated) {
|
||||
LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
itr->second->refcount++;
|
||||
@@ -175,10 +188,10 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
params.handle = itr->first;
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
|
||||
|
||||
IocParamParams params;
|
||||
@@ -189,12 +202,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
auto object = GetObject(params.handle);
|
||||
if (!object) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
if (object->status != Object::Status::Allocated) {
|
||||
LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
switch (static_cast<ParamTypes>(params.param)) {
|
||||
@@ -216,10 +229,10 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
// TODO(Subv): These flags are unconfirmed.
|
||||
enum FreeFlags {
|
||||
Freed = 0,
|
||||
@@ -234,14 +247,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
auto itr = handles.find(params.handle);
|
||||
if (itr == handles.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
if (!itr->second->refcount) {
|
||||
LOG_ERROR(
|
||||
Service_NVDRV,
|
||||
"There is no references to this object. The object is already freed. handle={:08X}",
|
||||
params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
itr->second->refcount--;
|
||||
@@ -261,7 +274,7 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
handles.erase(params.handle);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -19,13 +19,17 @@ public:
|
||||
explicit nvmap(Core::System& system);
|
||||
~nvmap() override;
|
||||
|
||||
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) override;
|
||||
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output, IoctlCtrl& ctrl) override;
|
||||
|
||||
/// Returns the allocated address of an nvmap object given its handle.
|
||||
VAddr GetObjectAddress(u32 handle) const;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) override;
|
||||
|
||||
/// Represents an nvmap object.
|
||||
struct Object {
|
||||
enum class Status { Created, Allocated };
|
||||
@@ -58,76 +62,68 @@ private:
|
||||
/// Mapping of currently allocated handles to the objects they represent.
|
||||
std::unordered_map<u32, std::shared_ptr<Object>> handles;
|
||||
|
||||
enum class IoctlCommand : u32 {
|
||||
Create = 0xC0080101,
|
||||
FromId = 0xC0080103,
|
||||
Alloc = 0xC0200104,
|
||||
Free = 0xC0180105,
|
||||
Param = 0xC00C0109,
|
||||
GetId = 0xC008010E,
|
||||
};
|
||||
struct IocCreateParams {
|
||||
// Input
|
||||
u32_le size;
|
||||
u32_le size{};
|
||||
// Output
|
||||
u32_le handle;
|
||||
u32_le handle{};
|
||||
};
|
||||
static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size");
|
||||
|
||||
struct IocFromIdParams {
|
||||
// Input
|
||||
u32_le id;
|
||||
u32_le id{};
|
||||
// Output
|
||||
u32_le handle;
|
||||
u32_le handle{};
|
||||
};
|
||||
static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size");
|
||||
|
||||
struct IocAllocParams {
|
||||
// Input
|
||||
u32_le handle;
|
||||
u32_le heap_mask;
|
||||
u32_le flags;
|
||||
u32_le align;
|
||||
u8 kind;
|
||||
u32_le handle{};
|
||||
u32_le heap_mask{};
|
||||
u32_le flags{};
|
||||
u32_le align{};
|
||||
u8 kind{};
|
||||
INSERT_PADDING_BYTES(7);
|
||||
u64_le addr;
|
||||
u64_le addr{};
|
||||
};
|
||||
static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size");
|
||||
|
||||
struct IocFreeParams {
|
||||
u32_le handle;
|
||||
u32_le handle{};
|
||||
INSERT_PADDING_BYTES(4);
|
||||
u64_le address;
|
||||
u32_le size;
|
||||
u32_le flags;
|
||||
u64_le address{};
|
||||
u32_le size{};
|
||||
u32_le flags{};
|
||||
};
|
||||
static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");
|
||||
|
||||
struct IocParamParams {
|
||||
// Input
|
||||
u32_le handle;
|
||||
u32_le param;
|
||||
u32_le handle{};
|
||||
u32_le param{};
|
||||
// Output
|
||||
u32_le result;
|
||||
u32_le result{};
|
||||
};
|
||||
static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size");
|
||||
|
||||
struct IocGetIdParams {
|
||||
// Output
|
||||
u32_le id;
|
||||
u32_le id{};
|
||||
// Input
|
||||
u32_le handle;
|
||||
u32_le handle{};
|
||||
};
|
||||
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
|
||||
|
||||
u32 CreateObject(u32 size);
|
||||
|
||||
u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -23,41 +23,47 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
|
||||
void NVDRV::Open(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
const auto& buffer = ctx.ReadBuffer();
|
||||
std::string device_name(buffer.begin(), buffer.end());
|
||||
if (!is_initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& buffer = ctx.ReadBuffer();
|
||||
const std::string device_name(buffer.begin(), buffer.end());
|
||||
DeviceFD fd = nvdrv->Open(device_name);
|
||||
|
||||
u32 fd = nvdrv->Open(device_name);
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(fd);
|
||||
rb.Push<u32>(0);
|
||||
rb.Push<DeviceFD>(fd);
|
||||
rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
|
||||
}
|
||||
|
||||
void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) {
|
||||
void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(result);
|
||||
}
|
||||
|
||||
void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 fd = rp.Pop<u32>();
|
||||
u32 command = rp.Pop<u32>();
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto command = rp.PopRaw<Ioctl>();
|
||||
LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
|
||||
|
||||
/// Ioctl 3 has 2 outputs, first in the input params, second is the result
|
||||
std::vector<u8> output(ctx.GetWriteBufferSize(0));
|
||||
std::vector<u8> output2;
|
||||
if (version == IoctlVersion::Version3) {
|
||||
output2.resize((ctx.GetWriteBufferSize(1)));
|
||||
if (!is_initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
/// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer.
|
||||
/// KickOfPB uses this
|
||||
auto input = ctx.ReadBuffer(0);
|
||||
|
||||
std::vector<u8> input2;
|
||||
if (version == IoctlVersion::Version2) {
|
||||
input2 = ctx.ReadBuffer(1);
|
||||
}
|
||||
// Check device
|
||||
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||
const auto input_buffer = ctx.ReadBuffer(0);
|
||||
|
||||
IoctlCtrl ctrl{};
|
||||
|
||||
u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version);
|
||||
|
||||
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer, ctrl);
|
||||
if (ctrl.must_delay) {
|
||||
ctrl.fresh_call = false;
|
||||
ctx.SleepClientThread(
|
||||
@@ -65,82 +71,195 @@ void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) {
|
||||
[=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
|
||||
Kernel::ThreadWakeupReason reason) {
|
||||
IoctlCtrl ctrl2{ctrl};
|
||||
std::vector<u8> tmp_output = output;
|
||||
std::vector<u8> tmp_output2 = output2;
|
||||
const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output,
|
||||
tmp_output2, ctrl2, version);
|
||||
ctx_.WriteBuffer(tmp_output, 0);
|
||||
if (version == IoctlVersion::Version3) {
|
||||
ctx_.WriteBuffer(tmp_output2, 1);
|
||||
std::vector<u8> tmp_output = output_buffer;
|
||||
const auto nv_result2 = nvdrv->Ioctl1(fd, command, input_buffer, tmp_output, ctrl2);
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(tmp_output);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx_, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(ioctl_result);
|
||||
rb.PushEnum(nv_result2);
|
||||
},
|
||||
nvdrv->GetEventWriteable(ctrl.event_id));
|
||||
} else {
|
||||
ctx.WriteBuffer(output);
|
||||
if (version == IoctlVersion::Version3) {
|
||||
ctx.WriteBuffer(output2, 1);
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlBase(ctx, IoctlVersion::Version1);
|
||||
rb.PushEnum(nv_result);
|
||||
}
|
||||
|
||||
void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlBase(ctx, IoctlVersion::Version2);
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto command = rp.PopRaw<Ioctl>();
|
||||
LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
|
||||
|
||||
if (!is_initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto input_buffer = ctx.ReadBuffer(0);
|
||||
const auto input_inlined_buffer = ctx.ReadBuffer(1);
|
||||
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||
|
||||
IoctlCtrl ctrl{};
|
||||
|
||||
const auto nv_result =
|
||||
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer, ctrl);
|
||||
if (ctrl.must_delay) {
|
||||
ctrl.fresh_call = false;
|
||||
ctx.SleepClientThread(
|
||||
"NVServices::DelayedResponse", ctrl.timeout,
|
||||
[=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
|
||||
Kernel::ThreadWakeupReason reason) {
|
||||
IoctlCtrl ctrl2{ctrl};
|
||||
std::vector<u8> tmp_output = output_buffer;
|
||||
const auto nv_result2 = nvdrv->Ioctl2(fd, command, input_buffer,
|
||||
input_inlined_buffer, tmp_output, ctrl2);
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(tmp_output);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx_, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result2);
|
||||
},
|
||||
nvdrv->GetEventWriteable(ctrl.event_id));
|
||||
} else {
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result);
|
||||
}
|
||||
|
||||
void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlBase(ctx, IoctlVersion::Version3);
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto command = rp.PopRaw<Ioctl>();
|
||||
LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
|
||||
|
||||
if (!is_initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto input_buffer = ctx.ReadBuffer(0);
|
||||
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||
std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1));
|
||||
|
||||
IoctlCtrl ctrl{};
|
||||
const auto nv_result =
|
||||
nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline, ctrl);
|
||||
if (ctrl.must_delay) {
|
||||
ctrl.fresh_call = false;
|
||||
ctx.SleepClientThread(
|
||||
"NVServices::DelayedResponse", ctrl.timeout,
|
||||
[=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
|
||||
Kernel::ThreadWakeupReason reason) {
|
||||
IoctlCtrl ctrl2{ctrl};
|
||||
std::vector<u8> tmp_output = output_buffer;
|
||||
std::vector<u8> tmp_output2 = output_buffer;
|
||||
const auto nv_result2 =
|
||||
nvdrv->Ioctl3(fd, command, input_buffer, tmp_output, tmp_output2, ctrl2);
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(tmp_output, 0);
|
||||
ctx.WriteBuffer(tmp_output2, 1);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx_, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result2);
|
||||
},
|
||||
nvdrv->GetEventWriteable(ctrl.event_id));
|
||||
} else {
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer, 0);
|
||||
ctx.WriteBuffer(output_buffer_inline, 1);
|
||||
}
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result);
|
||||
}
|
||||
|
||||
void NVDRV::Close(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
if (!is_initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 fd = rp.Pop<u32>();
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto result = nvdrv->Close(fd);
|
||||
|
||||
auto result = nvdrv->Close(fd);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(result);
|
||||
}
|
||||
|
||||
void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
is_initialized = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
}
|
||||
|
||||
void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 fd = rp.Pop<u32>();
|
||||
// TODO(Blinkhawk): Figure the meaning of the flag at bit 16
|
||||
u32 event_id = rp.Pop<u32>() & 0x000000FF;
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto event_id = rp.Pop<u32>() & 0x00FF;
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
if (!is_initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto nv_result = nvdrv->VerifyFD(fd);
|
||||
if (nv_result != NvResult::Success) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd);
|
||||
ServiceError(ctx, nv_result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event_id < MaxNvEvents) {
|
||||
IPC::ResponseBuilder rb{ctx, 3, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
auto event = nvdrv->GetEvent(event_id);
|
||||
event->Clear();
|
||||
rb.PushCopyObjects(event);
|
||||
rb.Push<u32>(NvResult::Success);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
} else {
|
||||
rb.Push<u32>(0);
|
||||
rb.Push<u32>(NvResult::BadParameter);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(NvResult::BadParameter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +270,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
}
|
||||
|
||||
void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
|
||||
@@ -164,8 +283,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct
|
||||
void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
}
|
||||
|
||||
void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
|
||||
@@ -181,7 +301,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||
: ServiceFramework(name), nvdrv(std::move(nvdrv)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NVDRV::Open, "Open"},
|
||||
{1, &NVDRV::Ioctl, "Ioctl"},
|
||||
{1, &NVDRV::Ioctl1, "Ioctl"},
|
||||
{2, &NVDRV::Close, "Close"},
|
||||
{3, &NVDRV::Initialize, "Initialize"},
|
||||
{4, &NVDRV::QueryEvent, "QueryEvent"},
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
|
||||
private:
|
||||
void Open(Kernel::HLERequestContext& ctx);
|
||||
void Ioctl(Kernel::HLERequestContext& ctx);
|
||||
void Ioctl1(Kernel::HLERequestContext& ctx);
|
||||
void Ioctl2(Kernel::HLERequestContext& ctx);
|
||||
void Ioctl3(Kernel::HLERequestContext& ctx);
|
||||
void Close(Kernel::HLERequestContext& ctx);
|
||||
@@ -33,11 +33,13 @@ private:
|
||||
void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);
|
||||
void GetStatus(Kernel::HLERequestContext& ctx);
|
||||
void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
|
||||
void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version);
|
||||
|
||||
void ServiceError(Kernel::HLERequestContext& ctx, NvResult result);
|
||||
|
||||
std::shared_ptr<Module> nvdrv;
|
||||
|
||||
u64 pid{};
|
||||
bool is_initialized{};
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::Nvidia {
|
||||
|
||||
constexpr u32 MaxSyncPoints = 192;
|
||||
constexpr u32 MaxNvEvents = 64;
|
||||
using DeviceFD = s32;
|
||||
|
||||
constexpr DeviceFD INVALID_NVDRV_FD = -1;
|
||||
|
||||
struct Fence {
|
||||
s32 id;
|
||||
@@ -20,11 +24,61 @@ struct MultiFence {
|
||||
std::array<Fence, 4> fences;
|
||||
};
|
||||
|
||||
enum NvResult : u32 {
|
||||
Success = 0,
|
||||
BadParameter = 4,
|
||||
Timeout = 5,
|
||||
ResourceError = 15,
|
||||
enum class NvResult : u32 {
|
||||
Success = 0x0,
|
||||
NotImplemented = 0x1,
|
||||
NotSupported = 0x2,
|
||||
NotInitialized = 0x3,
|
||||
BadParameter = 0x4,
|
||||
Timeout = 0x5,
|
||||
InsufficientMemory = 0x6,
|
||||
ReadOnlyAttribute = 0x7,
|
||||
InvalidState = 0x8,
|
||||
InvalidAddress = 0x9,
|
||||
InvalidSize = 0xA,
|
||||
BadValue = 0xB,
|
||||
AlreadyAllocated = 0xD,
|
||||
Busy = 0xE,
|
||||
ResourceError = 0xF,
|
||||
CountMismatch = 0x10,
|
||||
OverFlow = 0x11,
|
||||
InsufficientTransferMemory = 0x1000,
|
||||
InsufficientVideoMemory = 0x10000,
|
||||
BadSurfaceColorScheme = 0x10001,
|
||||
InvalidSurface = 0x10002,
|
||||
SurfaceNotSupported = 0x10003,
|
||||
DispInitFailed = 0x20000,
|
||||
DispAlreadyAttached = 0x20001,
|
||||
DispTooManyDisplays = 0x20002,
|
||||
DispNoDisplaysAttached = 0x20003,
|
||||
DispModeNotSupported = 0x20004,
|
||||
DispNotFound = 0x20005,
|
||||
DispAttachDissallowed = 0x20006,
|
||||
DispTypeNotSupported = 0x20007,
|
||||
DispAuthenticationFailed = 0x20008,
|
||||
DispNotAttached = 0x20009,
|
||||
DispSamePwrState = 0x2000A,
|
||||
DispEdidFailure = 0x2000B,
|
||||
DispDsiReadAckError = 0x2000C,
|
||||
DispDsiReadInvalidResp = 0x2000D,
|
||||
FileWriteFailed = 0x30000,
|
||||
FileReadFailed = 0x30001,
|
||||
EndOfFile = 0x30002,
|
||||
FileOperationFailed = 0x30003,
|
||||
DirOperationFailed = 0x30004,
|
||||
EndOfDirList = 0x30005,
|
||||
ConfigVarNotFound = 0x30006,
|
||||
InvalidConfigVar = 0x30007,
|
||||
LibraryNotFound = 0x30008,
|
||||
SymbolNotFound = 0x30009,
|
||||
MemoryMapFailed = 0x3000A,
|
||||
IoctlFailed = 0x3000F,
|
||||
AccessDenied = 0x30010,
|
||||
DeviceNotFound = 0x30011,
|
||||
KernelDriverNotFound = 0x30012,
|
||||
FileNotFound = 0x30013,
|
||||
PathAlreadyExists = 0x30014,
|
||||
ModuleNotPresent = 0xA000E,
|
||||
};
|
||||
|
||||
enum class EventState {
|
||||
@@ -34,10 +88,13 @@ enum class EventState {
|
||||
Busy = 3,
|
||||
};
|
||||
|
||||
enum class IoctlVersion : u32 {
|
||||
Version1,
|
||||
Version2,
|
||||
Version3,
|
||||
union Ioctl {
|
||||
u32_le raw;
|
||||
BitField<0, 8, u32> cmd;
|
||||
BitField<8, 8, u32> group;
|
||||
BitField<16, 14, u32> length;
|
||||
BitField<30, 1, u32> is_in;
|
||||
BitField<31, 1, u32> is_out;
|
||||
};
|
||||
|
||||
struct IoctlCtrl {
|
||||
|
||||
@@ -62,36 +62,102 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
|
||||
|
||||
Module::~Module() = default;
|
||||
|
||||
u32 Module::Open(const std::string& device_name) {
|
||||
ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}",
|
||||
device_name);
|
||||
NvResult Module::VerifyFD(DeviceFD fd) const {
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
|
||||
if (open_files.find(fd) == open_files.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
DeviceFD Module::Open(const std::string& device_name) {
|
||||
if (devices.find(device_name) == devices.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);
|
||||
return INVALID_NVDRV_FD;
|
||||
}
|
||||
|
||||
auto device = devices[device_name];
|
||||
const u32 fd = next_fd++;
|
||||
const DeviceFD fd = next_fd++;
|
||||
|
||||
open_files[fd] = std::move(device);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version) {
|
||||
auto itr = open_files.find(fd);
|
||||
ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device");
|
||||
NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, IoctlCtrl& ctrl) {
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
|
||||
auto& device = itr->second;
|
||||
return device->ioctl({command}, input, input2, output, output2, ctrl, version);
|
||||
const auto itr = open_files.find(fd);
|
||||
|
||||
if (itr == open_files.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
return itr->second->Ioctl1(command, input, output, ctrl);
|
||||
}
|
||||
|
||||
ResultCode Module::Close(u32 fd) {
|
||||
auto itr = open_files.find(fd);
|
||||
ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device");
|
||||
NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output,
|
||||
IoctlCtrl& ctrl) {
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
|
||||
const auto itr = open_files.find(fd);
|
||||
|
||||
if (itr == open_files.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
return itr->second->Ioctl2(command, input, inline_input, output, ctrl);
|
||||
}
|
||||
|
||||
NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output, IoctlCtrl& ctrl) {
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
|
||||
const auto itr = open_files.find(fd);
|
||||
|
||||
if (itr == open_files.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
return itr->second->Ioctl3(command, input, output, inline_output, ctrl);
|
||||
}
|
||||
|
||||
NvResult Module::Close(DeviceFD fd) {
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
|
||||
const auto itr = open_files.find(fd);
|
||||
|
||||
if (itr == open_files.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
open_files.erase(itr);
|
||||
|
||||
// TODO(flerovium): return correct result code if operation failed.
|
||||
return RESULT_SUCCESS;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
|
||||
|
||||
@@ -112,14 +112,23 @@ public:
|
||||
return std::static_pointer_cast<T>(itr->second);
|
||||
}
|
||||
|
||||
NvResult VerifyFD(DeviceFD fd) const;
|
||||
|
||||
/// Opens a device node and returns a file descriptor to it.
|
||||
u32 Open(const std::string& device_name);
|
||||
DeviceFD Open(const std::string& device_name);
|
||||
|
||||
/// Sends an ioctl command to the specified file descriptor.
|
||||
u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
||||
IoctlVersion version);
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, IoctlCtrl& ctrl);
|
||||
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
const std::vector<u8>& inline_input, std::vector<u8>& output, IoctlCtrl& ctrl);
|
||||
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output, IoctlCtrl& ctrl);
|
||||
|
||||
/// Closes a device file descriptor and returns operation success.
|
||||
ResultCode Close(u32 fd);
|
||||
NvResult Close(DeviceFD fd);
|
||||
|
||||
void SignalSyncpt(const u32 syncpoint_id, const u32 value);
|
||||
|
||||
@@ -132,10 +141,10 @@ private:
|
||||
SyncpointManager syncpoint_manager;
|
||||
|
||||
/// Id to use for the next open file descriptor.
|
||||
u32 next_fd = 1;
|
||||
DeviceFD next_fd = 1;
|
||||
|
||||
/// Mapping of file descriptors to the devices they reference.
|
||||
std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files;
|
||||
std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files;
|
||||
|
||||
/// Mapping of device node names to their implementation.
|
||||
std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
* @returns The lower bound for the specified syncpoint.
|
||||
*/
|
||||
u32 GetSyncpointMin(u32 syncpoint_id) const {
|
||||
return syncpoints[syncpoint_id].min.load(std::memory_order_relaxed);
|
||||
return syncpoints.at(syncpoint_id).min.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
* @returns The upper bound for the specified syncpoint.
|
||||
*/
|
||||
u32 GetSyncpointMax(u32 syncpoint_id) const {
|
||||
return syncpoints[syncpoint_id].max.load(std::memory_order_relaxed);
|
||||
return syncpoints.at(syncpoint_id).max.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
69
src/core/hle/service/olsc/olsc.cpp
Normal file
69
src/core/hle/service/olsc/olsc.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/service/olsc/olsc.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::OLSC {
|
||||
|
||||
class OLSC final : public ServiceFramework<OLSC> {
|
||||
public:
|
||||
explicit OLSC() : ServiceFramework{"olsc:u"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &OLSC::Initialize, "Initialize"},
|
||||
{10, nullptr, "VerifySaveDataBackupLicenseAsync"},
|
||||
{13, nullptr, "GetSaveDataBackupSetting"},
|
||||
{14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
|
||||
{15, nullptr, "SetCustomData"},
|
||||
{16, nullptr, "DeleteSaveDataBackupSetting"},
|
||||
{18, nullptr, "GetSaveDataBackupInfoCache"},
|
||||
{19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
|
||||
{22, nullptr, "DeleteSaveDataBackupAsync"},
|
||||
{25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
|
||||
{26, nullptr, "DownloadSaveDataBackupAsync"},
|
||||
{9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
|
||||
{9013, nullptr, "GetSaveDataBackupSettingForDebug"},
|
||||
{9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
|
||||
{9015, nullptr, "SetCustomDataForDebug"},
|
||||
{9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
|
||||
{9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
|
||||
{9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
|
||||
{9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
|
||||
{9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
|
||||
{9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_OLSC, "(STUBBED) called");
|
||||
|
||||
initialized = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_OLSC, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
bool initialized{};
|
||||
};
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
std::make_shared<OLSC>()->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
} // namespace Service::OLSC
|
||||
16
src/core/hle/service/olsc/olsc.h
Normal file
16
src/core/hle/service/olsc/olsc.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
}
|
||||
|
||||
namespace Service::OLSC {
|
||||
|
||||
/// Registers all SSL services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager);
|
||||
|
||||
} // namespace Service::OLSC
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
#include "core/hle/service/nvflinger/nvflinger.h"
|
||||
#include "core/hle/service/olsc/olsc.h"
|
||||
#include "core/hle/service/pcie/pcie.h"
|
||||
#include "core/hle/service/pctl/module.h"
|
||||
#include "core/hle/service/pcv/pcv.h"
|
||||
@@ -187,17 +188,19 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/// Initialize ServiceManager
|
||||
void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
|
||||
/// Initialize Services
|
||||
Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system)
|
||||
: nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system)} {
|
||||
|
||||
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
|
||||
// here and pass it into the respective InstallInterfaces functions.
|
||||
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system);
|
||||
|
||||
system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
|
||||
|
||||
SM::ServiceManager::InstallInterfaces(sm, system.Kernel());
|
||||
|
||||
Account::InstallInterfaces(system);
|
||||
AM::InstallInterfaces(*sm, nv_flinger, system);
|
||||
AM::InstallInterfaces(*sm, *nv_flinger, system);
|
||||
AOC::InstallInterfaces(*sm, system);
|
||||
APM::InstallInterfaces(system);
|
||||
Audio::InstallInterfaces(*sm, system);
|
||||
@@ -231,6 +234,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
|
||||
NPNS::InstallInterfaces(*sm);
|
||||
NS::InstallInterfaces(*sm, system);
|
||||
Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
|
||||
OLSC::InstallInterfaces(*sm);
|
||||
PCIe::InstallInterfaces(*sm);
|
||||
PCTL::InstallInterfaces(*sm);
|
||||
PCV::InstallInterfaces(*sm);
|
||||
@@ -244,14 +248,10 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
|
||||
SSL::InstallInterfaces(*sm);
|
||||
Time::InstallInterfaces(system);
|
||||
USB::InstallInterfaces(*sm);
|
||||
VI::InstallInterfaces(*sm, nv_flinger);
|
||||
VI::InstallInterfaces(*sm, *nv_flinger);
|
||||
WLAN::InstallInterfaces(*sm);
|
||||
|
||||
LOG_DEBUG(Service, "initialized OK");
|
||||
}
|
||||
|
||||
/// Shutdown ServiceManager
|
||||
void Shutdown() {
|
||||
LOG_DEBUG(Service, "shutdown OK");
|
||||
}
|
||||
Services::~Services() = default;
|
||||
|
||||
} // namespace Service
|
||||
|
||||
@@ -29,7 +29,11 @@ namespace Service {
|
||||
|
||||
namespace FileSystem {
|
||||
class FileSystemController;
|
||||
} // namespace FileSystem
|
||||
}
|
||||
|
||||
namespace NVFlinger {
|
||||
class NVFlinger;
|
||||
}
|
||||
|
||||
namespace SM {
|
||||
class ServiceManager;
|
||||
@@ -181,10 +185,17 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
/// Initialize ServiceManager
|
||||
void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
|
||||
/**
|
||||
* The purpose of this class is to own any objects that need to be shared across the other service
|
||||
* implementations. Will be torn down when the global system instance is shutdown.
|
||||
*/
|
||||
class Services final {
|
||||
public:
|
||||
explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
|
||||
~Services();
|
||||
|
||||
/// Shutdown ServiceManager
|
||||
void Shutdown();
|
||||
private:
|
||||
std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;
|
||||
};
|
||||
|
||||
} // namespace Service
|
||||
|
||||
@@ -492,8 +492,8 @@ private:
|
||||
|
||||
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
|
||||
public:
|
||||
explicit IHOSBinderDriver(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
|
||||
: ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) {
|
||||
explicit IHOSBinderDriver(NVFlinger::NVFlinger& nv_flinger)
|
||||
: ServiceFramework("IHOSBinderDriver"), nv_flinger(nv_flinger) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
|
||||
{1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
|
||||
@@ -530,8 +530,8 @@ private:
|
||||
LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
|
||||
static_cast<u32>(transaction), flags);
|
||||
|
||||
const auto guard = nv_flinger->Lock();
|
||||
auto& buffer_queue = nv_flinger->FindBufferQueue(id);
|
||||
const auto guard = nv_flinger.Lock();
|
||||
auto& buffer_queue = nv_flinger.FindBufferQueue(id);
|
||||
|
||||
switch (transaction) {
|
||||
case TransactionId::Connect: {
|
||||
@@ -570,8 +570,8 @@ private:
|
||||
[=, this](std::shared_ptr<Kernel::Thread> thread,
|
||||
Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) {
|
||||
// Repeat TransactParcel DequeueBuffer when a buffer is available
|
||||
const auto guard = nv_flinger->Lock();
|
||||
auto& buffer_queue = nv_flinger->FindBufferQueue(id);
|
||||
const auto guard = nv_flinger.Lock();
|
||||
auto& buffer_queue = nv_flinger.FindBufferQueue(id);
|
||||
auto result = buffer_queue.DequeueBuffer(width, height);
|
||||
ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
|
||||
|
||||
@@ -676,7 +676,7 @@ private:
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
|
||||
|
||||
const auto& buffer_queue = nv_flinger->FindBufferQueue(id);
|
||||
const auto& buffer_queue = nv_flinger.FindBufferQueue(id);
|
||||
|
||||
// TODO(Subv): Find out what this actually is.
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
@@ -684,8 +684,8 @@ private:
|
||||
rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent());
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
|
||||
}; // namespace VI
|
||||
NVFlinger::NVFlinger& nv_flinger;
|
||||
};
|
||||
|
||||
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
|
||||
public:
|
||||
@@ -790,8 +790,8 @@ private:
|
||||
|
||||
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
|
||||
public:
|
||||
explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
|
||||
: ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) {
|
||||
explicit IManagerDisplayService(NVFlinger::NVFlinger& nv_flinger)
|
||||
: ServiceFramework("IManagerDisplayService"), nv_flinger(nv_flinger) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{200, nullptr, "AllocateProcessHeapBlock"},
|
||||
@@ -893,7 +893,7 @@ private:
|
||||
"(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
|
||||
unknown, display, aruid);
|
||||
|
||||
const auto layer_id = nv_flinger->CreateLayer(display);
|
||||
const auto layer_id = nv_flinger.CreateLayer(display);
|
||||
if (!layer_id) {
|
||||
LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -930,12 +930,12 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
|
||||
NVFlinger::NVFlinger& nv_flinger;
|
||||
};
|
||||
|
||||
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
|
||||
public:
|
||||
explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
explicit IApplicationDisplayService(NVFlinger::NVFlinger& nv_flinger);
|
||||
|
||||
private:
|
||||
enum class ConvertedScaleMode : u64 {
|
||||
@@ -1010,7 +1010,7 @@ private:
|
||||
|
||||
ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
|
||||
|
||||
const auto display_id = nv_flinger->OpenDisplay(name);
|
||||
const auto display_id = nv_flinger.OpenDisplay(name);
|
||||
if (!display_id) {
|
||||
LOG_ERROR(Service_VI, "Display not found! display_name={}", name);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -1110,7 +1110,7 @@ private:
|
||||
|
||||
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
|
||||
|
||||
const auto display_id = nv_flinger->OpenDisplay(display_name);
|
||||
const auto display_id = nv_flinger.OpenDisplay(display_name);
|
||||
if (!display_id) {
|
||||
LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -1118,7 +1118,7 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
const auto buffer_queue_id = nv_flinger->FindBufferQueueId(*display_id, layer_id);
|
||||
const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id);
|
||||
if (!buffer_queue_id) {
|
||||
LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -1138,7 +1138,7 @@ private:
|
||||
|
||||
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id);
|
||||
|
||||
nv_flinger->CloseLayer(layer_id);
|
||||
nv_flinger.CloseLayer(layer_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -1154,7 +1154,7 @@ private:
|
||||
|
||||
// TODO(Subv): What's the difference between a Stray and a Managed layer?
|
||||
|
||||
const auto layer_id = nv_flinger->CreateLayer(display_id);
|
||||
const auto layer_id = nv_flinger.CreateLayer(display_id);
|
||||
if (!layer_id) {
|
||||
LOG_ERROR(Service_VI, "Layer not found! layer_id={}", *layer_id);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -1162,7 +1162,7 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
const auto buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, *layer_id);
|
||||
const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id);
|
||||
if (!buffer_queue_id) {
|
||||
LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -1193,7 +1193,7 @@ private:
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id);
|
||||
|
||||
const auto vsync_event = nv_flinger->FindVsyncEvent(display_id);
|
||||
const auto vsync_event = nv_flinger.FindVsyncEvent(display_id);
|
||||
if (!vsync_event) {
|
||||
LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -1258,12 +1258,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
|
||||
NVFlinger::NVFlinger& nv_flinger;
|
||||
};
|
||||
|
||||
IApplicationDisplayService::IApplicationDisplayService(
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
|
||||
: ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) {
|
||||
IApplicationDisplayService::IApplicationDisplayService(NVFlinger::NVFlinger& nv_flinger)
|
||||
: ServiceFramework("IApplicationDisplayService"), nv_flinger(nv_flinger) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
|
||||
{101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
|
||||
@@ -1304,8 +1303,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger,
|
||||
void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, NVFlinger::NVFlinger& nv_flinger,
|
||||
Permission permission) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto policy = rp.PopEnum<Policy>();
|
||||
@@ -1319,11 +1317,10 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx,
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationDisplayService>(std::move(nv_flinger));
|
||||
rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger);
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) {
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nv_flinger) {
|
||||
std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager);
|
||||
std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager);
|
||||
std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager);
|
||||
|
||||
@@ -43,12 +43,11 @@ enum class Policy {
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, Permission permission);
|
||||
void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, NVFlinger::NVFlinger& nv_flinger,
|
||||
Permission permission);
|
||||
} // namespace detail
|
||||
|
||||
/// Registers all VI services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nv_flinger);
|
||||
|
||||
} // namespace Service::VI
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
namespace Service::VI {
|
||||
|
||||
VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
|
||||
: ServiceFramework{"vi:m"}, nv_flinger{std::move(nv_flinger)} {
|
||||
VI_M::VI_M(NVFlinger::NVFlinger& nv_flinger) : ServiceFramework{"vi:m"}, nv_flinger{nv_flinger} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{2, &VI_M::GetDisplayService, "GetDisplayService"},
|
||||
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
|
||||
|
||||
@@ -18,13 +18,13 @@ namespace Service::VI {
|
||||
|
||||
class VI_M final : public ServiceFramework<VI_M> {
|
||||
public:
|
||||
explicit VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
explicit VI_M(NVFlinger::NVFlinger& nv_flinger);
|
||||
~VI_M() override;
|
||||
|
||||
private:
|
||||
void GetDisplayService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
|
||||
NVFlinger::NVFlinger& nv_flinger;
|
||||
};
|
||||
|
||||
} // namespace Service::VI
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
namespace Service::VI {
|
||||
|
||||
VI_S::VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
|
||||
: ServiceFramework{"vi:s"}, nv_flinger{std::move(nv_flinger)} {
|
||||
VI_S::VI_S(NVFlinger::NVFlinger& nv_flinger) : ServiceFramework{"vi:s"}, nv_flinger{nv_flinger} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &VI_S::GetDisplayService, "GetDisplayService"},
|
||||
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
|
||||
|
||||
@@ -18,13 +18,13 @@ namespace Service::VI {
|
||||
|
||||
class VI_S final : public ServiceFramework<VI_S> {
|
||||
public:
|
||||
explicit VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
explicit VI_S(NVFlinger::NVFlinger& nv_flinger);
|
||||
~VI_S() override;
|
||||
|
||||
private:
|
||||
void GetDisplayService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
|
||||
NVFlinger::NVFlinger& nv_flinger;
|
||||
};
|
||||
|
||||
} // namespace Service::VI
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
namespace Service::VI {
|
||||
|
||||
VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
|
||||
: ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} {
|
||||
VI_U::VI_U(NVFlinger::NVFlinger& nv_flinger) : ServiceFramework{"vi:u"}, nv_flinger{nv_flinger} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &VI_U::GetDisplayService, "GetDisplayService"},
|
||||
{1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
|
||||
|
||||
@@ -18,13 +18,13 @@ namespace Service::VI {
|
||||
|
||||
class VI_U final : public ServiceFramework<VI_U> {
|
||||
public:
|
||||
explicit VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
explicit VI_U(NVFlinger::NVFlinger& nv_flinger);
|
||||
~VI_U() override;
|
||||
|
||||
private:
|
||||
void GetDisplayService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
|
||||
NVFlinger::NVFlinger& nv_flinger;
|
||||
};
|
||||
|
||||
} // namespace Service::VI
|
||||
|
||||
@@ -114,7 +114,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||
}
|
||||
|
||||
if (override_update) {
|
||||
const FileSys::PatchManager patch_manager(metadata.GetTitleID());
|
||||
const FileSys::PatchManager patch_manager(
|
||||
metadata.GetTitleID(), system.GetFileSystemController(), system.GetContentProvider());
|
||||
dir = patch_manager.PatchExeFS(dir);
|
||||
}
|
||||
|
||||
@@ -160,7 +161,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||
modules.clear();
|
||||
const VAddr base_address{process.PageTable().GetCodeRegionStart()};
|
||||
VAddr next_load_addr{base_address};
|
||||
const FileSys::PatchManager pm{metadata.GetTitleID()};
|
||||
const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
for (const auto& module : static_modules) {
|
||||
const FileSys::VirtualFile module_file{dir->GetFile(module)};
|
||||
if (!module_file) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/loader/deconstructed_rom_directory.h"
|
||||
#include "core/loader/elf.h"
|
||||
@@ -194,15 +195,15 @@ AppLoader::~AppLoader() = default;
|
||||
|
||||
/**
|
||||
* Get a loader for a file with a specific type
|
||||
* @param file The file to load
|
||||
* @param type The type of the file
|
||||
* @param file the file to retrieve the loader for
|
||||
* @param type the file type
|
||||
* @param system The system context to use.
|
||||
* @param file The file to retrieve the loader for
|
||||
* @param type The file type
|
||||
* @param program_index Specifies the index within the container of the program to launch.
|
||||
* @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type
|
||||
*/
|
||||
static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileType type) {
|
||||
static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file,
|
||||
FileType type, std::size_t program_index) {
|
||||
switch (type) {
|
||||
|
||||
// Standard ELF file format.
|
||||
case FileType::ELF:
|
||||
return std::make_unique<AppLoader_ELF>(std::move(file));
|
||||
@@ -221,7 +222,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
|
||||
|
||||
// NX XCI (nX Card Image) file format.
|
||||
case FileType::XCI:
|
||||
return std::make_unique<AppLoader_XCI>(std::move(file));
|
||||
return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(),
|
||||
system.GetContentProvider(), program_index);
|
||||
|
||||
// NX NAX (NintendoAesXts) file format.
|
||||
case FileType::NAX:
|
||||
@@ -229,7 +231,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
|
||||
|
||||
// NX NSP (Nintendo Submission Package) file format
|
||||
case FileType::NSP:
|
||||
return std::make_unique<AppLoader_NSP>(std::move(file));
|
||||
return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(),
|
||||
system.GetContentProvider(), program_index);
|
||||
|
||||
// NX KIP (Kernel Internal Process) file format
|
||||
case FileType::KIP:
|
||||
@@ -244,20 +247,22 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file) {
|
||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
|
||||
std::size_t program_index) {
|
||||
FileType type = IdentifyFile(file);
|
||||
FileType filename_type = GuessFromFilename(file->GetName());
|
||||
const FileType filename_type = GuessFromFilename(file->GetName());
|
||||
|
||||
// Special case: 00 is either a NCA or NAX.
|
||||
if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) {
|
||||
LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName());
|
||||
if (FileType::Unknown == type)
|
||||
if (FileType::Unknown == type) {
|
||||
type = filename_type;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type));
|
||||
|
||||
return GetFileLoader(std::move(file), type);
|
||||
return GetFileLoader(system, std::move(file), type, program_index);
|
||||
}
|
||||
|
||||
} // namespace Loader
|
||||
|
||||
@@ -290,9 +290,14 @@ protected:
|
||||
|
||||
/**
|
||||
* Identifies a bootable file and return a suitable loader
|
||||
* @param file The bootable file
|
||||
* @return the best loader for this file
|
||||
*
|
||||
* @param system The system context.
|
||||
* @param file The bootable file.
|
||||
* @param program_index Specifies the index within the container of the program to launch.
|
||||
*
|
||||
* @return the best loader for this file.
|
||||
*/
|
||||
std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file);
|
||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
|
||||
std::size_t program_index = 0);
|
||||
|
||||
} // namespace Loader
|
||||
|
||||
@@ -149,7 +149,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
|
||||
// Apply cheats if they exist and the program has a valid title ID
|
||||
if (pm) {
|
||||
system.SetCurrentProcessBuildID(nso_header.build_id);
|
||||
const auto cheats = pm->CreateCheatList(system, nso_header.build_id);
|
||||
const auto cheats = pm->CreateCheatList(nso_header.build_id);
|
||||
if (!cheats.empty()) {
|
||||
system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size);
|
||||
}
|
||||
|
||||
@@ -21,26 +21,34 @@
|
||||
|
||||
namespace Loader {
|
||||
|
||||
AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file)
|
||||
: AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)),
|
||||
AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
std::size_t program_index)
|
||||
: AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)),
|
||||
title_id(nsp->GetProgramTitleID()) {
|
||||
|
||||
if (nsp->GetStatus() != ResultStatus::Success)
|
||||
if (nsp->GetStatus() != ResultStatus::Success) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsp->IsExtractedType()) {
|
||||
secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS());
|
||||
} else {
|
||||
const auto control_nca =
|
||||
nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);
|
||||
if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success)
|
||||
if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::tie(nacp_file, icon_file) =
|
||||
FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca);
|
||||
std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] {
|
||||
const FileSys::PatchManager pm{nsp->GetProgramTitleID(), fsc, content_provider};
|
||||
return pm.ParseControlNCA(*control_nca);
|
||||
}();
|
||||
|
||||
if (title_id == 0)
|
||||
if (title_id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
secondary_loader = std::make_unique<AppLoader_NCA>(
|
||||
nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program));
|
||||
|
||||
@@ -9,15 +9,16 @@
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
class ContentProvider;
|
||||
class NACP;
|
||||
class NSP;
|
||||
} // namespace FileSys
|
||||
|
||||
namespace Service::FileSystem {
|
||||
class FileSystemController;
|
||||
}
|
||||
|
||||
namespace Loader {
|
||||
|
||||
class AppLoader_NCA;
|
||||
@@ -25,7 +26,10 @@ class AppLoader_NCA;
|
||||
/// Loads an XCI file
|
||||
class AppLoader_NSP final : public AppLoader {
|
||||
public:
|
||||
explicit AppLoader_NSP(FileSys::VirtualFile file);
|
||||
explicit AppLoader_NSP(FileSys::VirtualFile file,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
std::size_t program_index);
|
||||
~AppLoader_NSP() override;
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,18 +20,25 @@
|
||||
|
||||
namespace Loader {
|
||||
|
||||
AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
|
||||
: AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)),
|
||||
AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
std::size_t program_index)
|
||||
: AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)),
|
||||
nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) {
|
||||
if (xci->GetStatus() != ResultStatus::Success)
|
||||
if (xci->GetStatus() != ResultStatus::Success) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control);
|
||||
if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success)
|
||||
if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::tie(nacp_file, icon_file) =
|
||||
FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(*control_nca);
|
||||
std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] {
|
||||
const FileSys::PatchManager pm{xci->GetProgramTitleID(), fsc, content_provider};
|
||||
return pm.ParseControlNCA(*control_nca);
|
||||
}();
|
||||
}
|
||||
|
||||
AppLoader_XCI::~AppLoader_XCI() = default;
|
||||
|
||||
@@ -9,15 +9,16 @@
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
class ContentProvider;
|
||||
class NACP;
|
||||
class XCI;
|
||||
} // namespace FileSys
|
||||
|
||||
namespace Service::FileSystem {
|
||||
class FileSystemController;
|
||||
}
|
||||
|
||||
namespace Loader {
|
||||
|
||||
class AppLoader_NCA;
|
||||
@@ -25,7 +26,10 @@ class AppLoader_NCA;
|
||||
/// Loads an XCI file
|
||||
class AppLoader_XCI final : public AppLoader {
|
||||
public:
|
||||
explicit AppLoader_XCI(FileSys::VirtualFile file);
|
||||
explicit AppLoader_XCI(FileSys::VirtualFile file,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
std::size_t program_index);
|
||||
~AppLoader_XCI() override;
|
||||
|
||||
/**
|
||||
|
||||
@@ -215,6 +215,7 @@ struct Values {
|
||||
bool reporting_services;
|
||||
bool quest_flag;
|
||||
bool disable_macro_jit;
|
||||
bool extended_logging;
|
||||
|
||||
// Misceallaneous
|
||||
std::string log_filter;
|
||||
|
||||
@@ -147,7 +147,9 @@ TelemetrySession::~TelemetrySession() {
|
||||
}
|
||||
}
|
||||
|
||||
void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
|
||||
void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider) {
|
||||
// Log one-time top-level information
|
||||
AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId());
|
||||
|
||||
@@ -167,7 +169,10 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
|
||||
app_loader.ReadTitle(name);
|
||||
|
||||
if (name.empty()) {
|
||||
const auto metadata = FileSys::PatchManager(program_id).GetControlMetadata();
|
||||
const auto metadata = [&content_provider, &fsc, program_id] {
|
||||
const FileSys::PatchManager pm{program_id, fsc, content_provider};
|
||||
return pm.GetControlMetadata();
|
||||
}();
|
||||
if (metadata.first != nullptr) {
|
||||
name = metadata.first->GetApplicationName();
|
||||
}
|
||||
|
||||
@@ -7,10 +7,18 @@
|
||||
#include <string>
|
||||
#include "common/telemetry.h"
|
||||
|
||||
namespace FileSys {
|
||||
class ContentProvider;
|
||||
}
|
||||
|
||||
namespace Loader {
|
||||
class AppLoader;
|
||||
}
|
||||
|
||||
namespace Service::FileSystem {
|
||||
class FileSystemController;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
/**
|
||||
@@ -40,10 +48,14 @@ public:
|
||||
* - Title file format
|
||||
* - Miscellaneous settings values.
|
||||
*
|
||||
* @param app_loader The application loader to use to retrieve
|
||||
* title-specific information.
|
||||
* @param app_loader The application loader to use to retrieve
|
||||
* title-specific information.
|
||||
* @param fsc Filesystem controller to use to retrieve info.
|
||||
* @param content_provider Content provider to use to retrieve info.
|
||||
*/
|
||||
void AddInitialInfo(Loader::AppLoader& app_loader);
|
||||
void AddInitialInfo(Loader::AppLoader& app_loader,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider);
|
||||
|
||||
/**
|
||||
* Wrapper around the Telemetry::FieldCollection::AddField method.
|
||||
|
||||
@@ -31,6 +31,9 @@ add_library(input_common STATIC
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(input_common PRIVATE
|
||||
/W4
|
||||
/WX
|
||||
|
||||
# 'expression' : signed/unsigned mismatch
|
||||
/we4018
|
||||
# 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
|
||||
@@ -46,14 +49,15 @@ if (MSVC)
|
||||
)
|
||||
else()
|
||||
target_compile_options(input_common PRIVATE
|
||||
-Werror
|
||||
-Werror=conversion
|
||||
-Werror=ignored-qualifiers
|
||||
-Werror=implicit-fallthrough
|
||||
-Werror=reorder
|
||||
-Werror=shadow
|
||||
-Werror=sign-compare
|
||||
-Werror=unused-but-set-parameter
|
||||
-Werror=unused-but-set-variable
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
|
||||
-Werror=unused-variable
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <thread>
|
||||
#include "common/math_util.h"
|
||||
#include "input_common/analog_from_button.h"
|
||||
|
||||
namespace InputCommon {
|
||||
@@ -11,31 +15,104 @@ public:
|
||||
using Button = std::unique_ptr<Input::ButtonDevice>;
|
||||
|
||||
Analog(Button up_, Button down_, Button left_, Button right_, Button modifier_,
|
||||
float modifier_scale_)
|
||||
float modifier_scale_, float modifier_angle_)
|
||||
: up(std::move(up_)), down(std::move(down_)), left(std::move(left_)),
|
||||
right(std::move(right_)), modifier(std::move(modifier_)),
|
||||
modifier_scale(modifier_scale_) {}
|
||||
right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_),
|
||||
modifier_angle(modifier_angle_) {
|
||||
update_thread = std::thread(&Analog::UpdateStatus, this);
|
||||
}
|
||||
|
||||
~Analog() override {
|
||||
update_thread_running = false;
|
||||
if (update_thread.joinable()) {
|
||||
update_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void MoveToDirection(bool enable, float to_angle) {
|
||||
if (!enable) {
|
||||
return;
|
||||
}
|
||||
constexpr float TAU = Common::PI * 2.0f;
|
||||
// Use wider angle to ease the transition.
|
||||
constexpr float aperture = TAU * 0.15f;
|
||||
const float top_limit = to_angle + aperture;
|
||||
const float bottom_limit = to_angle - aperture;
|
||||
|
||||
if ((angle > to_angle && angle <= top_limit) ||
|
||||
(angle + TAU > to_angle && angle + TAU <= top_limit)) {
|
||||
angle -= modifier_angle;
|
||||
if (angle < 0) {
|
||||
angle += TAU;
|
||||
}
|
||||
} else if ((angle >= bottom_limit && angle < to_angle) ||
|
||||
(angle - TAU >= bottom_limit && angle - TAU < to_angle)) {
|
||||
angle += modifier_angle;
|
||||
if (angle >= TAU) {
|
||||
angle -= TAU;
|
||||
}
|
||||
} else {
|
||||
angle = to_angle;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateStatus() {
|
||||
while (update_thread_running) {
|
||||
const float coef = modifier->GetStatus() ? modifier_scale : 1.0f;
|
||||
|
||||
bool r = right->GetStatus();
|
||||
bool l = left->GetStatus();
|
||||
bool u = up->GetStatus();
|
||||
bool d = down->GetStatus();
|
||||
|
||||
// Eliminate contradictory movements
|
||||
if (r && l) {
|
||||
r = false;
|
||||
l = false;
|
||||
}
|
||||
if (u && d) {
|
||||
u = false;
|
||||
d = false;
|
||||
}
|
||||
|
||||
// Move to the right
|
||||
MoveToDirection(r && !u && !d, 0.0f);
|
||||
|
||||
// Move to the upper right
|
||||
MoveToDirection(r && u && !d, Common::PI * 0.25f);
|
||||
|
||||
// Move up
|
||||
MoveToDirection(u && !l && !r, Common::PI * 0.5f);
|
||||
|
||||
// Move to the upper left
|
||||
MoveToDirection(l && u && !d, Common::PI * 0.75f);
|
||||
|
||||
// Move to the left
|
||||
MoveToDirection(l && !u && !d, Common::PI);
|
||||
|
||||
// Move to the bottom left
|
||||
MoveToDirection(l && !u && d, Common::PI * 1.25f);
|
||||
|
||||
// Move down
|
||||
MoveToDirection(d && !l && !r, Common::PI * 1.5f);
|
||||
|
||||
// Move to the bottom right
|
||||
MoveToDirection(r && !u && d, Common::PI * 1.75f);
|
||||
|
||||
// Move if a key is pressed
|
||||
if (r || l || u || d) {
|
||||
amplitude = coef;
|
||||
} else {
|
||||
amplitude = 0;
|
||||
}
|
||||
|
||||
// Delay the update rate to 100hz
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<float, float> GetStatus() const override {
|
||||
constexpr float SQRT_HALF = 0.707106781f;
|
||||
int x = 0, y = 0;
|
||||
|
||||
if (right->GetStatus()) {
|
||||
++x;
|
||||
}
|
||||
if (left->GetStatus()) {
|
||||
--x;
|
||||
}
|
||||
if (up->GetStatus()) {
|
||||
++y;
|
||||
}
|
||||
if (down->GetStatus()) {
|
||||
--y;
|
||||
}
|
||||
|
||||
const float coef = modifier->GetStatus() ? modifier_scale : 1.0f;
|
||||
return std::make_tuple(static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF),
|
||||
static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF));
|
||||
return std::make_tuple(std::cos(angle) * amplitude, std::sin(angle) * amplitude);
|
||||
}
|
||||
|
||||
bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
|
||||
@@ -59,6 +136,11 @@ private:
|
||||
Button right;
|
||||
Button modifier;
|
||||
float modifier_scale;
|
||||
float modifier_angle;
|
||||
float angle{};
|
||||
float amplitude{};
|
||||
std::thread update_thread;
|
||||
bool update_thread_running{true};
|
||||
};
|
||||
|
||||
std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) {
|
||||
@@ -69,8 +151,10 @@ std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::Para
|
||||
auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine));
|
||||
auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine));
|
||||
auto modifier_scale = params.Get("modifier_scale", 0.5f);
|
||||
auto modifier_angle = params.Get("modifier_angle", 0.035f);
|
||||
return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left),
|
||||
std::move(right), std::move(modifier), modifier_scale);
|
||||
std::move(right), std::move(modifier), modifier_scale,
|
||||
modifier_angle);
|
||||
}
|
||||
|
||||
} // namespace InputCommon
|
||||
|
||||
@@ -96,7 +96,6 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param
|
||||
adapter.get());
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -300,10 +299,11 @@ public:
|
||||
return gcadapter->RumblePlay(port, 0);
|
||||
}
|
||||
|
||||
bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
|
||||
bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high,
|
||||
[[maybe_unused]] f32 freq_high) const override {
|
||||
const auto mean_amplitude = (amp_low + amp_high) * 0.5f;
|
||||
const auto processed_amplitude = static_cast<u8>(
|
||||
pow(mean_amplitude, 0.5f) * (3.0f - 2.0f * pow(mean_amplitude, 0.15f)) * 0x8);
|
||||
const auto processed_amplitude =
|
||||
static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8);
|
||||
|
||||
return gcadapter->RumblePlay(port, processed_amplitude);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
/// Unregisters SDL device factories and shut them down.
|
||||
virtual ~State() = default;
|
||||
|
||||
virtual Pollers GetPollers(Polling::DeviceType type) {
|
||||
virtual Pollers GetPollers(Polling::DeviceType) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -400,10 +400,10 @@ public:
|
||||
return joystick->RumblePlay(0, 0);
|
||||
}
|
||||
|
||||
bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
|
||||
bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high,
|
||||
[[maybe_unused]] f32 freq_high) const override {
|
||||
const auto process_amplitude = [](f32 amplitude) {
|
||||
return static_cast<u16>(std::pow(amplitude, 0.5f) *
|
||||
(3.0f - 2.0f * std::pow(amplitude, 0.15f)) * 0xFFFF);
|
||||
return static_cast<u16>((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF);
|
||||
};
|
||||
|
||||
const auto processed_amp_low = process_amplitude(amp_low);
|
||||
@@ -865,6 +865,8 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve
|
||||
Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
|
||||
const SDL_GameControllerButtonBind& binding) {
|
||||
switch (binding.bindType) {
|
||||
case SDL_CONTROLLER_BINDTYPE_NONE:
|
||||
break;
|
||||
case SDL_CONTROLLER_BINDTYPE_AXIS:
|
||||
return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
|
||||
case SDL_CONTROLLER_BINDTYPE_BUTTON:
|
||||
@@ -985,7 +987,7 @@ class SDLPoller : public InputCommon::Polling::DevicePoller {
|
||||
public:
|
||||
explicit SDLPoller(SDLState& state_) : state(state_) {}
|
||||
|
||||
void Start(const std::string& device_id) override {
|
||||
void Start([[maybe_unused]] const std::string& device_id) override {
|
||||
state.event_queue.Clear();
|
||||
state.polling = true;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,7 @@ private:
|
||||
std::vector<std::tuple<std::unique_ptr<Input::ButtonDevice>, int, int>> map;
|
||||
};
|
||||
|
||||
std::unique_ptr<Input::TouchDevice> TouchFromButtonFactory::Create(
|
||||
const Common::ParamPackage& params) {
|
||||
std::unique_ptr<Input::TouchDevice> TouchFromButtonFactory::Create(const Common::ParamPackage&) {
|
||||
return std::make_unique<TouchFromButtonDevice>();
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user