Introduce Custom Span Class + IPC Buffer -> Span

This commit is contained in:
◱ PixelyIon 2020-09-25 05:35:12 +05:30 committed by ◱ PixelyIon
parent 4d6ae9aa26
commit 20559c5dca
55 changed files with 352 additions and 365 deletions

View File

@ -139,9 +139,8 @@ extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setTouchSta
auto input = inputWeak.lock();
jboolean isCopy{false};
std::span<Point> points(reinterpret_cast<Point *>(env->GetIntArrayElements(pointsJni, &isCopy)), env->GetArrayLength(pointsJni) / (sizeof(Point) / sizeof(jint)));
skyline::span<Point> points(reinterpret_cast<Point *>(env->GetIntArrayElements(pointsJni, &isCopy)), env->GetArrayLength(pointsJni) / (sizeof(Point) / sizeof(jint)));
input->touch.SetState(points);
env->ReleaseIntArrayElements(pointsJni, reinterpret_cast<jint *>(points.data()), JNI_ABORT);
} catch (const std::bad_weak_ptr &) {
// We don't mind if we miss axis updates while input hasn't been initialized

View File

@ -9,7 +9,7 @@
namespace skyline::audio {
AdpcmDecoder::AdpcmDecoder(const std::vector<std::array<i16, 2>> &coefficients) : coefficients(coefficients) {}
std::vector<i16> AdpcmDecoder::Decode(std::span<u8> adpcmData) {
std::vector<i16> AdpcmDecoder::Decode(span<u8> adpcmData) {
constexpr size_t BytesPerFrame{0x8};
constexpr size_t SamplesPerFrame{0xE};

View File

@ -37,6 +37,6 @@ namespace skyline::audio {
* @param adpcmData A buffer containing the raw ADPCM data
* @return A buffer containing decoded single channel I16 PCM data
*/
std::vector<i16> Decode(std::span<u8> adpcmData);
std::vector<i16> Decode(span<u8> adpcmData);
};
}

View File

@ -146,7 +146,7 @@ namespace skyline::audio {
* @brief This appends data from a span to the buffer
* @param data A span containing the data to be appended
*/
inline void Append(std::span<Type> data) {
inline void Append(span<Type> data) {
Append(data.data(), data.size());
}
};

View File

@ -121,7 +121,7 @@ namespace skyline::audio {
{-42, 3751, 26253, 2811}, {-38, 3608, 26270, 2936}, {-34, 3467, 26281, 3064}, {-32, 3329, 26287, 3195}}};
// @fmt:on
std::vector<i16> Resampler::ResampleBuffer(std::span<i16> inputBuffer, double ratio, u8 channelCount) {
std::vector<i16> Resampler::ResampleBuffer(span<i16> inputBuffer, double ratio, u8 channelCount) {
auto step{static_cast<u32>(ratio * 0x8000)};
auto outputSize{static_cast<size_t>(inputBuffer.size() / ratio)};
std::vector<i16> outputBuffer(outputSize);

View File

@ -21,6 +21,6 @@ namespace skyline::audio {
* @param ratio The conversion ratio needed
* @param channelCount The amount of channels the buffer contains
*/
std::vector<i16> ResampleBuffer(std::span<i16> inputBuffer, double ratio, u8 channelCount);
std::vector<i16> ResampleBuffer(span<i16> inputBuffer, double ratio, u8 channelCount);
};
}

View File

@ -44,7 +44,7 @@ namespace skyline::audio {
return bufferIds;
}
void AudioTrack::AppendBuffer(u64 tag, std::span<i16> buffer) {
void AudioTrack::AppendBuffer(u64 tag, span<i16> buffer) {
BufferIdentifier identifier{
.released = false,
.tag = tag,

View File

@ -66,7 +66,7 @@ namespace skyline::audio {
* @param tag The tag of the buffer
* @param buffer A span containing the source sample buffer
*/
void AppendBuffer(u64 tag, std::span<i16> buffer = {});
void AppendBuffer(u64 tag, span<i16> buffer = {});
/**
* @brief Checks if any buffers have been released and calls the appropriate callback for them

View File

@ -105,13 +105,7 @@ namespace skyline {
}
/**
* @brief Aligns up a value to a multiple of two
* @tparam Type The type of the values
* @param value The value to round up
* @param multiple The multiple to round up to (Should be a multiple of 2)
* @tparam TypeVal The type of the value
* @tparam TypeMul The type of the multiple
* @return The aligned value
* @return The value aligned up to the next multiple
*/
template<typename TypeVal, typename TypeMul>
constexpr inline TypeVal AlignUp(TypeVal value, TypeMul multiple) {
@ -120,12 +114,7 @@ namespace skyline {
}
/**
* @brief Aligns down a value to a multiple of two
* @param value The value to round down
* @param multiple The multiple to round down to (Should be a multiple of 2)
* @tparam TypeVal The type of the value
* @tparam TypeMul The type of the multiple
* @return The aligned value
* @return The value aligned down to the previous multiple
*/
template<typename TypeVal, typename TypeMul>
constexpr inline TypeVal AlignDown(TypeVal value, TypeMul multiple) {
@ -133,10 +122,7 @@ namespace skyline {
}
/**
* @param value The value to check for alignment
* @param multiple The multiple to check alignment with
* @return If the address is aligned with the multiple
* @note The multiple must be divisible by 2
*/
template<typename TypeVal, typename TypeMul>
constexpr inline bool IsAligned(TypeVal value, TypeMul multiple) {
@ -147,7 +133,6 @@ namespace skyline {
}
/**
* @param value The value to check for alignment
* @return If the value is page aligned
*/
constexpr inline bool PageAligned(u64 value) {
@ -155,7 +140,6 @@ namespace skyline {
}
/**
* @param value The value to check for alignment
* @return If the value is word aligned
*/
constexpr inline bool WordAligned(u64 value) {
@ -201,25 +185,118 @@ namespace skyline {
return result;
}
/**
* @brief A compile-time hash function as std::hash isn't constexpr
*/
constexpr std::size_t Hash(std::string_view view) {
return frz::elsa<frz::string>{}(frz::string(view.data(), view.size()), 0);
}
template<typename Out, typename In>
constexpr Out &As(std::span<In> span) {
if (IsAligned(span.size_bytes(), sizeof(Out)))
return *reinterpret_cast<Out *>(span.data());
throw exception("Span size not aligned with Out type size (0x{:X}/0x{:X})", span.size_bytes(), sizeof(Out));
}
template<typename Out, typename In>
constexpr std::span<Out> AsSpan(std::span<In> span) {
if (IsAligned(span.size_bytes(), sizeof(Out)))
return std::span(reinterpret_cast<Out *>(span.data()), span.size_bytes() / sizeof(Out));
throw exception("Span size not aligned with Out type size (0x{:X}/0x{:X})", span.size_bytes(), sizeof(Out));
/**
* @brief A custom wrapper over span that adds several useful methods to it
* @note This class is completely transparent, it implicitly converts from and to span
*/
template<typename T, size_t Extent = std::dynamic_extent>
class span : public std::span<T, Extent> {
public:
using std::span<T, Extent>::span;
using std::span<T, Extent>::operator=;
typedef typename std::span<T, Extent>::element_type elementType;
typedef typename std::span<T, Extent>::index_type indexType;
constexpr span(const std::span<T, Extent> &spn) : std::span<T, Extent>(spn) {}
/**
* @brief We want to support implicitly casting from std::string_view -> span as it is just a specialization of a data view which span is a generic form of, the opposite doesn't hold true as not all data held by a span is string data therefore the conversion isn't implicit there
*/
template<class Traits>
constexpr span(const std::basic_string_view<T, Traits> &string) : std::span<T, Extent>(const_cast<T *>(string.data()), string.size()) {}
template<typename Out>
constexpr Out &as() {
if (span::size_bytes() >= sizeof(Out))
return *reinterpret_cast<Out *>(span::data());
throw exception("Span size is less than Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out));
}
constexpr std::string_view as_string(indexType length = 0) {
return std::string_view(reinterpret_cast<char *>(span::data()), length ? length : span::size_bytes());
}
template<typename Out, size_t OutExtent = std::dynamic_extent>
constexpr span<Out> cast() {
if (util::IsAligned(span::size_bytes(), sizeof(Out)))
return span<Out, OutExtent>(reinterpret_cast<Out *>(span::data()), span::size_bytes() / sizeof(Out));
throw exception("Span size not aligned with Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out));
}
/**
* @brief Copies data from the supplied span into this one
* @param amount The amount of elements that need to be copied (in terms of the supplied span), 0 will try to copy the entirety of the other span
*/
template<typename In, size_t InExtent>
constexpr void copy_from(const span<In, InExtent> spn, indexType amount = 0) {
auto size{amount ? amount * sizeof(In) : spn.size_bytes()};
if (span::size_bytes() < size)
throw exception("Data being copied is larger than this span");
std::memmove(span::data(), spn.data(), size);
}
/**
* @brief Implicit type conversion for copy_from, this allows passing in std::vector/std::array in directly is automatically passed by reference which is important for any containers
*/
template<typename In>
constexpr void copy_from(const In &in, indexType amount = 0) {
copy_from(span<typename std::add_const<typename In::value_type>::type>(in), amount);
}
/** Base Class Functions that return an instance of it, we upcast them **/
template<size_t Count>
constexpr span<T, Count> first() const noexcept {
return std::span<T, Extent>::template first<Count>();
}
template<size_t Count>
constexpr span<T, Count> last() const noexcept {
return std::span<T, Extent>::template last<Count>();
}
constexpr span<elementType, std::dynamic_extent> first(indexType count) const noexcept {
return std::span<T, Extent>::first(count);
}
constexpr span<elementType, std::dynamic_extent> last(indexType count) const noexcept {
return std::span<T, Extent>::last(count);
}
template<size_t Offset, size_t Count = std::dynamic_extent>
constexpr auto subspan() const noexcept -> span<T, Count != std::dynamic_extent ? Count : Extent - Offset> {
return std::span<T, Extent>::template subspan<Offset, Count>();
}
constexpr span<T, std::dynamic_extent> subspan(indexType offset, indexType count = std::dynamic_extent) const noexcept {
return std::span<T, Extent>::subspan(offset, count);
}
};
/**
* @brief Deduction guides required for arguments to span, CTAD will fail for iterators, arrays and containers without this
*/
template<class It, class End, size_t Extent = std::dynamic_extent>
span(It, End) -> span<typename std::iterator_traits<It>::value_type, Extent>;
template<class T, size_t Size>
span(T (&)[Size]) -> span<T, Size>;
template<class T, size_t Size>
span(std::array<T, Size> &) -> span<T, Size>;
template<class T, size_t Size>
span(const std::array<T, Size> &) -> span<const T, Size>;
template<class Container>
span(Container &) -> span<typename Container::value_type>;
template<class Container>
span(const Container &) -> span<const typename Container::value_type>;
/**
* @brief The Mutex class is a wrapper around an atomic bool used for synchronization
*/

View File

@ -4,7 +4,7 @@
#include "aes_cipher.h"
namespace skyline::crypto {
AesCipher::AesCipher(std::span<u8> key, mbedtls_cipher_type_t type) {
AesCipher::AesCipher(span<u8> key, mbedtls_cipher_type_t type) {
mbedtls_cipher_init(&decryptContext);
if (mbedtls_cipher_setup(&decryptContext, mbedtls_cipher_info_from_type(type)) != 0)
throw exception("Failed to setup decryption context");

View File

@ -37,7 +37,7 @@ namespace skyline::crypto {
}
public:
AesCipher(std::span<u8> key, mbedtls_cipher_type_t type);
AesCipher(span<u8> key, mbedtls_cipher_type_t type);
~AesCipher();
@ -54,7 +54,7 @@ namespace skyline::crypto {
/**
* @brief Decrypts data and writes back to it
*/
inline void Decrypt(std::span<u8> data) {
inline void Decrypt(span<u8> data) {
Decrypt(data.data(), data.data(), data.size());
}
@ -66,7 +66,7 @@ namespace skyline::crypto {
/**
* @brief Decrypts data with XTS and writes back to it
*/
inline void XtsDecrypt(std::span<u8> data, size_t sector, size_t sectorSize) {
inline void XtsDecrypt(span<u8> data, size_t sector, size_t sectorSize) {
XtsDecrypt(data.data(), data.data(), data.size(), sector, sectorSize);
}
};

View File

@ -89,7 +89,7 @@ namespace skyline::gpu::gpfifo {
}
}
void GPFIFO::Push(std::span<GpEntry> entries) {
void GPFIFO::Push(span<GpEntry> entries) {
std::lock_guard lock(pushBufferQueueLock);
bool beforeBarrier{false};

View File

@ -173,7 +173,7 @@ namespace skyline::gpu {
/**
* @brief Pushes a list of entries to the FIFO, these commands will be executed on calls to 'Step'
*/
void Push(std::span<GpEntry> entries);
void Push(span<GpEntry> entries);
};
}
}

View File

@ -111,7 +111,7 @@ namespace skyline {
* @tparam T The type of span to read into
*/
template<typename T>
void Read(std::span<T> destination, u64 address) const {
void Read(span<T> destination, u64 address) const {
Read(reinterpret_cast<u8 *>(destination.data()), address, destination.size_bytes());
}
@ -132,7 +132,7 @@ namespace skyline {
* @brief Writes out a span to a region of the GPU virtual address space
*/
template<typename T>
void Write(std::span<T> source, u64 address) const {
void Write(span<T> source, u64 address) const {
Write(reinterpret_cast<u8 *>(source.data()), address, source.size_bytes());
}

View File

@ -412,7 +412,7 @@ namespace skyline::input {
amplitudes[i] = std::min(totalAmplitude, constant::AmplitudeMax);
}
jvm->VibrateDevice(index, std::span(timings.begin(), timings.begin() + i), std::span(amplitudes.begin(), amplitudes.begin() + i));
jvm->VibrateDevice(index, span(timings.begin(), timings.begin() + i), span(amplitudes.begin(), amplitudes.begin() + i));
}
void VibrateDevice(const std::shared_ptr<JvmManager> &jvm, i8 index, const NpadVibrationValue &value) {

View File

@ -14,7 +14,7 @@ namespace skyline::input {
SetState({});
}
void TouchManager::SetState(const std::span<TouchScreenPoint> &points) {
void TouchManager::SetState(const span<TouchScreenPoint> &points) {
if (!activated)
return;

View File

@ -37,6 +37,6 @@ namespace skyline::input {
void Activate();
void SetState(const std::span<TouchScreenPoint> &points);
void SetState(const span<TouchScreenPoint> &points);
};
}

View File

@ -47,7 +47,7 @@ namespace skyline {
env->CallVoidMethod(instance, initializeControllersId);
}
void JvmManager::VibrateDevice(jint index, const std::span<jlong> &timings, const std::span<jint> &amplitudes) {
void JvmManager::VibrateDevice(jint index, const span<jlong> &timings, const span<jint> &amplitudes) {
auto jTimings = env->NewLongArray(timings.size());
env->SetLongArrayRegion(jTimings, 0, timings.size(), timings.data());
auto jAmplitudes = env->NewIntArray(amplitudes.size());

View File

@ -97,7 +97,7 @@ namespace skyline {
/**
* @brief A call to EmulationActivity.vibrateDevice in Kotlin
*/
void VibrateDevice(jint index, const std::span<jlong> &timings, const std::span<jint> &amplitudes);
void VibrateDevice(jint index, const span<jlong> &timings, const span<jint> &amplitudes);
/**
* @brief A call to EmulationActivity.clearVibrationDevice in Kotlin

View File

@ -5,16 +5,6 @@
#include "types/KProcess.h"
namespace skyline::kernel::ipc {
IpcBuffer::IpcBuffer(u64 address, size_t size, IpcBufferType type) : address(address), size(size), type(type) {}
InputBuffer::InputBuffer(kernel::ipc::BufferDescriptorX *xBuf) : IpcBuffer(xBuf->Address(), xBuf->size, IpcBufferType::X) {}
InputBuffer::InputBuffer(kernel::ipc::BufferDescriptorABW *aBuf, IpcBufferType type) : IpcBuffer(aBuf->Address(), aBuf->Size(), type) {}
OutputBuffer::OutputBuffer(kernel::ipc::BufferDescriptorABW *bBuf, IpcBufferType type) : IpcBuffer(bBuf->Address(), bBuf->Size(), type) {}
OutputBuffer::OutputBuffer(kernel::ipc::BufferDescriptorC *cBuf) : IpcBuffer(cBuf->address, cBuf->size, IpcBufferType::C) {}
IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain) {
u8 *tls = state.process->GetPointer<u8>(state.thread->tls);
u8 *pointer = tls;
@ -40,7 +30,7 @@ namespace skyline::kernel::ipc {
for (u8 index = 0; header->xNo > index; index++) {
auto bufX = reinterpret_cast<BufferDescriptorX *>(pointer);
if (bufX->Address()) {
inputBuf.emplace_back(bufX);
inputBuf.emplace_back(state.process->GetPointer<u8>(bufX->Address()), u16(bufX->size));
state.logger->Debug("Buf X #{} AD: 0x{:X} SZ: 0x{:X} CTR: {}", index, u64(bufX->Address()), u16(bufX->size), u16(bufX->Counter()));
}
pointer += sizeof(BufferDescriptorX);
@ -49,7 +39,7 @@ namespace skyline::kernel::ipc {
for (u8 index = 0; header->aNo > index; index++) {
auto bufA = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufA->Address()) {
inputBuf.emplace_back(bufA);
inputBuf.emplace_back(state.process->GetPointer<u8>(bufA->Address()), bufA->Size());
state.logger->Debug("Buf A #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufA->Address()), u64(bufA->Size()));
}
pointer += sizeof(BufferDescriptorABW);
@ -58,7 +48,7 @@ namespace skyline::kernel::ipc {
for (u8 index = 0; header->bNo > index; index++) {
auto bufB = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufB->Address()) {
outputBuf.emplace_back(bufB);
outputBuf.emplace_back(state.process->GetPointer<u8>(bufB->Address()), bufB->Size());
state.logger->Debug("Buf B #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufB->Address()), u64(bufB->Size()));
}
pointer += sizeof(BufferDescriptorABW);
@ -67,8 +57,8 @@ namespace skyline::kernel::ipc {
for (u8 index = 0; header->wNo > index; index++) {
auto bufW = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufW->Address()) {
inputBuf.emplace_back(bufW, IpcBufferType::W);
outputBuf.emplace_back(bufW, IpcBufferType::W);
outputBuf.emplace_back(state.process->GetPointer<u8>(bufW->Address()), bufW->Size());
outputBuf.emplace_back(state.process->GetPointer<u8>(bufW->Address()), bufW->Size());
state.logger->Debug("Buf W #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufW->Address()), u16(bufW->Size()));
}
pointer += sizeof(BufferDescriptorABW);
@ -112,14 +102,14 @@ namespace skyline::kernel::ipc {
if (header->cFlag == BufferCFlag::SingleDescriptor) {
auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer);
if (bufC->address) {
outputBuf.emplace_back(bufC);
outputBuf.emplace_back(state.process->GetPointer<u8>(bufC->address), u16(bufC->size));
state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size));
}
} else if (header->cFlag > BufferCFlag::SingleDescriptor) {
for (u8 index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present
auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer);
if (bufC->address) {
outputBuf.emplace_back(bufC);
outputBuf.emplace_back(state.process->GetPointer<u8>(bufC->address), u16(bufC->size));
state.logger->Debug("Buf C #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufC->address), u16(bufC->size));
}
pointer += sizeof(BufferDescriptorC);

View File

@ -196,52 +196,6 @@ namespace skyline {
C //!< This is a type-C buffer
};
/**
* @brief Describes a buffer by holding the address and size
*/
struct IpcBuffer {
u64 address; //!< The address of the buffer
size_t size; //!< The size of the buffer
IpcBufferType type; //!< The type of the buffer
/**
* @param address The address of the buffer
* @param size The size of the buffer
* @param type The type of the buffer
*/
IpcBuffer(u64 address, size_t size, IpcBufferType type);
};
/**
* @brief This holds an input IPC buffer
*/
struct InputBuffer : public IpcBuffer {
/**
* @param aBuf The X Buffer Descriptor that has contains the input data
*/
InputBuffer(kernel::ipc::BufferDescriptorX *xBuf);
/**
* @param aBuf The A or W Buffer Descriptor that has contains the input data
*/
InputBuffer(kernel::ipc::BufferDescriptorABW *aBuf, IpcBufferType type = IpcBufferType::A);
};
/**
* @brief This holds an output IPC buffer
*/
struct OutputBuffer : public IpcBuffer {
/**
* @param bBuf The B or W Buffer Descriptor that has to be outputted to
*/
OutputBuffer(kernel::ipc::BufferDescriptorABW *bBuf, IpcBufferType type = IpcBufferType::B);
/**
* @param cBuf The C Buffer Descriptor that has to be outputted to
*/
OutputBuffer(kernel::ipc::BufferDescriptorC *cBuf);
};
/**
* @brief This class encapsulates an IPC Request (https://switchbrew.org/wiki/IPC_Marshalling)
*/
@ -260,8 +214,8 @@ namespace skyline {
std::vector<KHandle> copyHandles; //!< A vector of handles that should be copied from the server to the client process (The difference is just to match application expectations, there is no real difference b/w copying and moving handles)
std::vector<KHandle> moveHandles; //!< A vector of handles that should be moved from the server to the client process rather than copied
std::vector<KHandle> domainObjects; //!< A vector of all input domain objects
std::vector<InputBuffer> inputBuf; //!< This is a vector of input buffers
std::vector<OutputBuffer> outputBuf; //!< This is a vector of output buffers
std::vector<span<u8>> inputBuf; //!< This is a vector of input buffers
std::vector<span<u8>> outputBuf; //!< This is a vector of output buffers
/**
* @param isDomain If the following request is a domain request

View File

@ -24,7 +24,7 @@ namespace skyline::service::account {
try {
// We only support one active user currently so hardcode this and ListOpenUsers
return WriteUserList(request.outputBuf.at(0), {constant::DefaultUserId});
} catch (const std::out_of_range &e) {
} catch (const std::out_of_range &) {
return result::InvalidInputBuffer;
}
}
@ -32,14 +32,13 @@ namespace skyline::service::account {
Result IAccountServiceForApplication::ListOpenUsers(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
try {
return WriteUserList(request.outputBuf.at(0), {constant::DefaultUserId});
} catch (const std::out_of_range &e) {
} catch (const std::out_of_range &) {
return result::InvalidInputBuffer;
}
}
Result IAccountServiceForApplication::WriteUserList(ipc::OutputBuffer buffer, std::vector<UserId> userIds) {
std::span outputUserIds(state.process->GetPointer<UserId>(buffer.address), buffer.size / sizeof(UserId));
Result IAccountServiceForApplication::WriteUserList(span<u8> buffer, std::vector<UserId> userIds) {
span outputUserIds{buffer.cast<UserId>()};
for (auto &userId : outputUserIds) {
if (userIds.empty()) {
userId = UserId{};

View File

@ -39,7 +39,7 @@ namespace skyline {
/**
* @brief Writes a vector of 128-bit user IDs to an output buffer
*/
Result WriteUserList(ipc::OutputBuffer buffer, std::vector<UserId> userIds);
Result WriteUserList(span<u8> buffer, std::vector<UserId> userIds);
public:
IAccountServiceForApplication(const DeviceState &state, ServiceManager &manager);

View File

@ -17,8 +17,7 @@ namespace skyline::service::account {
u8 _unk2_[0x60];
};
auto userData = state.process->GetPointer<AccountUserData>(request.outputBuf.at(0).address);
userData->iconBackgroundColorID = 0x1; // Color indexing starts at 0x1
request.outputBuf.at(0).as<AccountUserData>().iconBackgroundColorID = 0x1; // Color indexing starts at 0x1
return GetBase(session, request, response);
}

View File

@ -15,26 +15,26 @@ namespace skyline::service::am {
Result IStorageAccessor::Write(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto offset = request.Pop<i64>();
auto size = std::min(static_cast<i64>(request.inputBuf.at(0).size), static_cast<i64>(parent->content.size()) - offset);
auto size = std::min(static_cast<i64>(request.inputBuf.at(0).size()), static_cast<i64>(parent->content.size()) - offset);
if (offset > parent->content.size())
return result::OutOfBounds;
if (size > 0)
state.process->ReadMemory(parent->content.data() + offset, request.inputBuf.at(0).address, size);
if (size)
request.outputBuf.at(0).copy_from(span(parent->content.data() + offset, size));
return {};
}
Result IStorageAccessor::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto offset = request.Pop<i64>();
auto size = std::min(static_cast<i64>(request.inputBuf.at(0).size), static_cast<i64>(parent->content.size()) - offset);
auto size = std::min(static_cast<i64>(request.inputBuf.at(0).size()), static_cast<i64>(parent->content.size()) - offset);
if (offset > parent->content.size())
return result::OutOfBounds;
if (size > 0)
state.process->WriteMemory(parent->content.data() + offset, request.outputBuf.at(0).address, size);
request.outputBuf.at(0).copy_from(span(parent->content.data() + offset, size));
return {};
}

View File

@ -9,13 +9,12 @@ namespace skyline::service::audio {
IAudioDevice::IAudioDevice(const DeviceState &state, ServiceManager &manager) : systemEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager) {}
Result IAudioDevice::ListAudioDeviceName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
u64 offset{};
for (std::string deviceName : {"AudioTvOutput", "AudioStereoJackOutput", "AudioBuiltInSpeakerOutput"}) {
if (offset + deviceName.size() + 1 > request.outputBuf.at(0).size)
throw exception("Too small a buffer supplied to ListAudioDeviceName");
state.process->WriteMemory(deviceName.c_str(), request.outputBuf.at(0).address + offset, deviceName.size() + 1);
offset += deviceName.size() + 1;
span buffer{request.outputBuf.at(0)};
for (std::string_view deviceName : {"AudioTvOutput\0", "AudioStereoJackOutput\0", "AudioBuiltInSpeakerOutput\0"}) {
if (deviceName.size() > buffer.size())
throw exception("The buffer supplied to ListAudioDeviceName is too small");
buffer.copy_from(deviceName);
buffer = buffer.subspan(deviceName.size());
}
return {};
}
@ -25,12 +24,10 @@ namespace skyline::service::audio {
}
Result IAudioDevice::GetActiveAudioDeviceName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
std::string deviceName("AudioStereoJackOutput");
if (deviceName.size() > request.outputBuf.at(0).size)
throw exception("Too small a buffer supplied to GetActiveAudioDeviceName");
state.process->WriteMemory(deviceName.c_str(), request.outputBuf.at(0).address, deviceName.size() + 1);
std::string_view deviceName{"AudioStereoJackOutput\0"};
if (deviceName.size() > request.outputBuf.at(0).size())
throw exception("The buffer supplied to GetActiveAudioDeviceName is too small");
request.outputBuf.at(0).copy_from(deviceName);
return {};
}

View File

@ -37,16 +37,16 @@ namespace skyline::service::audio {
u64 sampleCapacity;
u64 sampleSize;
u64 sampleOffset;
} &data{state.process->GetReference<Data>(request.inputBuf.at(0).address)};
} &data{request.inputBuf.at(0).as<Data>()};
auto tag = request.Pop<u64>();
state.logger->Debug("IAudioOut: Appending buffer with address: 0x{:X}, size: 0x{:X}", data.sampleBufferPtr, data.sampleSize);
if (sampleRate != constant::SampleRate) {
auto resampledBuffer = resampler.ResampleBuffer(std::span(state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize / sizeof(i16)), static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
auto resampledBuffer = resampler.ResampleBuffer(span(state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize / sizeof(i16)), static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
track->AppendBuffer(tag, resampledBuffer);
} else {
track->AppendBuffer(tag, std::span(state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize / sizeof(i16)));
track->AppendBuffer(tag, span(state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize / sizeof(i16)));
}
return {};
@ -60,13 +60,13 @@ namespace skyline::service::audio {
}
Result IAudioOut::GetReleasedAudioOutBuffer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto maxCount{static_cast<u32>(request.outputBuf.at(0).size >> 3)};
auto maxCount{static_cast<u32>(request.outputBuf.at(0).size() >> 3)};
std::vector<u64> releasedBuffers{track->GetReleasedBuffers(maxCount)};
auto count{static_cast<u32>(releasedBuffers.size())};
// Fill rest of output buffer with zeros
releasedBuffers.resize(maxCount, 0);
state.process->WriteMemory(releasedBuffers.data(), request.outputBuf.at(0).address, request.outputBuf.at(0).size);
request.outputBuf.at(0).copy_from(releasedBuffers);
response.Push<u32>(count);
return {};

View File

@ -9,7 +9,7 @@ namespace skyline::service::audio {
IAudioOutManager::IAudioOutManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
Result IAudioOutManager::ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
state.process->WriteMemory(reinterpret_cast<void *>(const_cast<char *>(constant::DefaultAudioOutName.data())), request.outputBuf.at(0).address, constant::DefaultAudioOutName.size());
request.outputBuf.at(0).copy_from(constant::DefaultAudioOutName);
return {};
}

View File

@ -45,32 +45,26 @@ namespace skyline::service::audio::IAudioRenderer {
}
Result IAudioRenderer::RequestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto inputAddress{request.inputBuf.at(0).address};
auto input{request.inputBuf.at(0).data()};
auto inputHeader{state.process->GetObject<UpdateDataHeader>(inputAddress)};
auto inputHeader{*reinterpret_cast<UpdateDataHeader *>(input)};
revisionInfo.SetUserRevision(inputHeader.revision);
inputAddress += sizeof(UpdateDataHeader);
inputAddress += inputHeader.behaviorSize; // Unused
input += sizeof(UpdateDataHeader);
input += inputHeader.behaviorSize; // Unused
auto memoryPoolCount{memoryPools.size()};
std::vector<MemoryPoolIn> memoryPoolsIn(memoryPoolCount);
state.process->ReadMemory(memoryPoolsIn.data(), inputAddress, memoryPoolCount * sizeof(MemoryPoolIn));
inputAddress += inputHeader.memoryPoolSize;
for (auto i = 0; i < memoryPoolsIn.size(); i++)
span memoryPoolsIn(reinterpret_cast<MemoryPoolIn*>(input), memoryPools.size());
input += inputHeader.memoryPoolSize;
for (auto i = 0; i < memoryPools.size(); i++)
memoryPools[i].ProcessInput(memoryPoolsIn[i]);
inputAddress += inputHeader.voiceResourceSize;
std::vector<VoiceIn> voicesIn(parameters.voiceCount);
state.process->ReadMemory(voicesIn.data(), inputAddress, parameters.voiceCount * sizeof(VoiceIn));
inputAddress += inputHeader.voiceSize;
input += inputHeader.voiceResourceSize;
span voicesIn(reinterpret_cast<VoiceIn*>(input), parameters.voiceCount);
input += inputHeader.voiceSize;
for (auto i = 0; i < voicesIn.size(); i++)
voices[i].ProcessInput(voicesIn[i]);
std::vector<EffectIn> effectsIn(parameters.effectCount);
state.process->ReadMemory(effectsIn.data(), inputAddress, parameters.effectCount * sizeof(EffectIn));
span effectsIn(reinterpret_cast<EffectIn*>(input), parameters.effectCount);
for (auto i = 0; i < effectsIn.size(); i++)
effects[i].ProcessInput(effectsIn[i]);
@ -100,24 +94,24 @@ namespace skyline::service::audio::IAudioRenderer {
outputHeader.performanceManagerSize +
outputHeader.elapsedFrameCountInfoSize;
u64 outputAddress = request.outputBuf.at(0).address;
auto output{request.outputBuf.at(0).data()};
state.process->WriteMemory(outputHeader, outputAddress);
outputAddress += sizeof(UpdateDataHeader);
*reinterpret_cast<UpdateDataHeader*>(output) = outputHeader;
output += sizeof(UpdateDataHeader);
for (const auto &memoryPool : memoryPools) {
state.process->WriteMemory(memoryPool.output, outputAddress);
outputAddress += sizeof(MemoryPoolOut);
*reinterpret_cast<MemoryPoolOut*>(output) = memoryPool.output;
output += sizeof(MemoryPoolOut);
}
for (const auto &voice : voices) {
state.process->WriteMemory(voice.output, outputAddress);
outputAddress += sizeof(VoiceOut);
*reinterpret_cast<VoiceOut*>(output) = voice.output;
output += sizeof(VoiceOut);
}
for (const auto &effect : effects) {
state.process->WriteMemory(effect.output, outputAddress);
outputAddress += sizeof(EffectOut);
*reinterpret_cast<EffectOut*>(output) = effect.output;
output += sizeof(EffectOut);
}
return {};

View File

@ -68,7 +68,7 @@ namespace skyline::service::audio::IAudioRenderer {
state.process->ReadMemory(samples.data(), currentBuffer.address, currentBuffer.size);
break;
case skyline::audio::AudioFormat::ADPCM: {
samples = adpcmDecoder->Decode(std::span(state.process->GetPointer<u8>(currentBuffer.address), currentBuffer.size));
samples = adpcmDecoder->Decode(span(state.process->GetPointer<u8>(currentBuffer.address), currentBuffer.size));
break;
}
default:

View File

@ -6,30 +6,24 @@
#include "parcel.h"
namespace skyline::service {
Parcel::Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state, bool hasToken) : Parcel(buffer.address, buffer.size, state, hasToken) {}
Parcel::Parcel(span<u8> buffer, const DeviceState &state, bool hasToken) : state(state) {
header = buffer.as<ParcelHeader>();
Parcel::Parcel(u64 address, u64 size, const DeviceState &state, bool hasToken) : state(state) {
state.process->ReadMemory(&header, address, sizeof(ParcelHeader));
if (size < (sizeof(ParcelHeader) + header.dataSize + header.objectsSize))
if (buffer.size() < (sizeof(ParcelHeader) + header.dataSize + header.objectsSize))
throw exception("The size of the parcel according to the header exceeds the specified size");
constexpr auto tokenLength = 0x50; // The length of the token on BufferQueue parcels
data.resize(header.dataSize - (hasToken ? tokenLength : 0));
state.process->ReadMemory(data.data(), address + header.dataOffset + (hasToken ? tokenLength : 0), header.dataSize - (hasToken ? tokenLength : 0));
memcpy(data.data(), buffer.data() + header.dataOffset + (hasToken ? tokenLength : 0), header.dataSize - (hasToken ? tokenLength : 0));
objects.resize(header.objectsSize);
state.process->ReadMemory(objects.data(), address + header.objectsOffset, header.objectsSize);
memcpy(objects.data(), buffer.data() + header.objectsOffset, header.objectsSize);
}
Parcel::Parcel(const DeviceState &state) : state(state) {}
u64 Parcel::WriteParcel(kernel::ipc::OutputBuffer &buffer) {
return WriteParcel(buffer.address, buffer.size);
}
u64 Parcel::WriteParcel(u64 address, u64 maxSize) {
u64 Parcel::WriteParcel(span<u8> buffer) {
header.dataSize = static_cast<u32>(data.size());
header.dataOffset = sizeof(ParcelHeader);
@ -38,12 +32,12 @@ namespace skyline::service {
auto totalSize = sizeof(ParcelHeader) + header.dataSize + header.objectsSize;
if (maxSize < totalSize)
if (buffer.size() < totalSize)
throw exception("The size of the parcel exceeds maxSize");
state.process->WriteMemory(header, address);
state.process->WriteMemory(data.data(), address + header.dataOffset, data.size());
state.process->WriteMemory(objects.data(), address + header.objectsOffset, objects.size());
buffer.as<ParcelHeader>() = header;
memcpy(buffer.data() + header.dataOffset, data.data(), data.size());
memcpy(buffer.data() + header.objectsOffset, objects.data(), objects.size());
return totalSize;
}

View File

@ -36,16 +36,7 @@ namespace skyline::service {
* @param state The state of the device
* @param hasToken If the parcel starts with a token, it is skipped if this flag is true
*/
Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state, bool hasToken = false);
/**
* @brief This constructor fills in the Parcel object with data from a Parcel on a remote process
* @param address The remote address of the parcel
* @param size The size of the parcel
* @param state The state of the device
* @param hasToken If the parcel starts with a token, it is skipped if this flag is true
*/
Parcel(u64 address, u64 size, const DeviceState &state, bool hasToken = false);
Parcel(span<u8> buffer, const DeviceState &state, bool hasToken = false);
/**
* @brief This constructor is used to create an empty parcel then write to a process
@ -94,18 +85,10 @@ namespace skyline::service {
}
/**
* @brief Writes the Parcel object into a particular output buffer on a process
* @param buffer The buffer to write into
* @brief Writes the Parcel object out
* @param buffer The buffer to write the Parcel object to
* @return The total size of the message
*/
u64 WriteParcel(kernel::ipc::OutputBuffer &buffer);
/**
* @brief Writes the Parcel object into the process's memory
* @param address The address to write the Parcel object to
* @param maxSize The maximum size of the Parcel
* @return The total size of the message
*/
u64 WriteParcel(u64 address, u64 maxSize);
u64 WriteParcel(span<u8> buffer);
};
}

View File

@ -24,7 +24,7 @@ namespace skyline::service::fssrv {
return result::InvalidSize;
}
response.Push<u32>(static_cast<u32>(backing->Read(state.process->GetPointer<u8>(request.outputBuf.at(0).address), offset, size)));
response.Push<u32>(static_cast<u32>(backing->Read(request.outputBuf.at(0).data(), offset, size)));
return {};
}
@ -44,12 +44,12 @@ namespace skyline::service::fssrv {
return result::InvalidSize;
}
if (request.inputBuf.at(0).size < size) {
if (request.inputBuf.at(0).size() < size) {
state.logger->Warn("The input buffer is not large enough to fit the requested size");
return result::InvalidSize;
}
if (backing->Write(state.process->GetPointer<u8>(request.inputBuf.at(0).address), offset, request.inputBuf.at(0).size) != size) {
if (backing->Write(request.inputBuf.at(0).data(), offset, request.inputBuf.at(0).size()) != size) {
state.logger->Warn("Failed to write all data to the backing");
return result::UnexpectedFailure;
}

View File

@ -11,7 +11,7 @@ namespace skyline::service::fssrv {
IFileSystem::IFileSystem(std::shared_ptr<vfs::FileSystem> backing, const DeviceState &state, ServiceManager &manager) : backing(backing), BaseService(state, manager) {}
Result IFileSystem::CreateFile(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
std::string path = std::string(state.process->GetPointer<char>(request.inputBuf.at(0).address));
std::string path{request.inputBuf.at(0).as<char>()};
auto mode = request.Pop<u64>();
auto size = request.Pop<u32>();
@ -19,7 +19,7 @@ namespace skyline::service::fssrv {
}
Result IFileSystem::GetEntryType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
std::string path = std::string(state.process->GetPointer<char>(request.inputBuf.at(0).address));
std::string path{request.inputBuf.at(0).as<char>()};
auto type = backing->GetEntryType(path);
@ -33,7 +33,7 @@ namespace skyline::service::fssrv {
}
Result IFileSystem::OpenFile(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
std::string path(state.process->GetPointer<char>(request.inputBuf.at(0).address));
std::string path{request.inputBuf.at(0).as<char>()};
auto mode = request.Pop<vfs::Backing::Mode>();
if (!backing->FileExists(path))

View File

@ -22,7 +22,7 @@ namespace skyline::service::fssrv {
return result::InvalidSize;
}
backing->Read(state.process->GetPointer<u8>(request.outputBuf.at(0).address), offset, size);
backing->Read(request.outputBuf.at(0).data(), offset, size);
return {};
}

View File

@ -41,18 +41,9 @@ namespace skyline::service::hid {
}
Result IHidServer::SetSupportedNpadIdType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
const auto &buffer = request.inputBuf.at(0);
u64 address = buffer.address;
size_t size = buffer.size / sizeof(NpadId);
std::vector<NpadId> supportedIds(size);
for (size_t i = 0; i < size; i++) {
supportedIds[i] = state.process->GetObject<NpadId>(address);
address += sizeof(NpadId);
}
auto supportedIds{request.inputBuf.at(0).cast<NpadId>()};
std::lock_guard lock(state.input->npad.mutex);
state.input->npad.supportedIds = supportedIds;
state.input->npad.supportedIds.assign(supportedIds.begin(), supportedIds.end());
state.input->npad.Update();
return {};
}
@ -150,10 +141,8 @@ namespace skyline::service::hid {
Result IHidServer::SendVibrationValues(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
request.Skip<u64>(); // appletResourceUserId
auto &handleBuf = request.inputBuf.at(0);
std::span handles(reinterpret_cast<NpadDeviceHandle *>(handleBuf.address), handleBuf.size / sizeof(NpadDeviceHandle));
auto &valueBuf = request.inputBuf.at(1);
std::span values(reinterpret_cast<NpadVibrationValue *>(valueBuf.address), valueBuf.size / sizeof(NpadVibrationValue));
auto handles{request.inputBuf.at(0).cast<NpadDeviceHandle>()};
auto values{request.inputBuf.at(1).cast<NpadVibrationValue>()};
for (size_t i{}; i < handles.size(); ++i) {
const auto &handle = handles[i];

View File

@ -40,16 +40,16 @@ namespace skyline::service::lm {
LogLevel level;
u8 verbosity;
u32 payloadLength;
} &data = state.process->GetReference<Data>(request.inputBuf.at(0).address);
} &data = request.inputBuf.at(0).as<Data>();
std::ostringstream logMessage;
logMessage << "Guest log:";
u64 offset = sizeof(Data);
while (offset < request.inputBuf.at(0).size) {
auto fieldType = state.process->GetObject<LogFieldType>(request.inputBuf.at(0).address + offset++);
auto length = state.process->GetObject<u8>(request.inputBuf.at(0).address + offset++);
auto address = request.inputBuf.at(0).address + offset;
while (offset < request.inputBuf[0].size()) {
auto fieldType = request.inputBuf[0].subspan(offset++).as<LogFieldType>();
auto length = request.inputBuf[0].subspan(offset++).as<u8>();
auto object = request.inputBuf[0].subspan(offset, length);
logMessage << " ";
@ -58,24 +58,25 @@ namespace skyline::service::lm {
offset += length;
continue;
case LogFieldType::Line:
logMessage << GetFieldName(fieldType) << ": " << state.process->GetObject<u32>(address);
logMessage << GetFieldName(fieldType) << ": " << object.as<u32>();
offset += sizeof(u32);
continue;
case LogFieldType::DropCount:
logMessage << GetFieldName(fieldType) << ": " << state.process->GetObject<u64>(address);
logMessage << GetFieldName(fieldType) << ": " << object.as<u64>();
offset += sizeof(u64);
continue;
case LogFieldType::Time:
logMessage << GetFieldName(fieldType) << ": " << state.process->GetObject<u64>(address) << "s";
logMessage << GetFieldName(fieldType) << ": " << object.as<u64>() << "s";
offset += sizeof(u64);
continue;
case LogFieldType::Stop:
break;
default:
logMessage << GetFieldName(fieldType) << ": " << state.process->GetString(address, length);
logMessage << GetFieldName(fieldType) << ": " << object.as_string();
offset += length;
continue;
}
break;
}

View File

@ -13,8 +13,7 @@ namespace skyline::service::nvdrv {
}
Result INvDrvServices::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto buffer = request.inputBuf.at(0);
auto path = state.process->GetString(buffer.address, buffer.size);
auto path{request.inputBuf.at(0).as_string()};
response.Push<u32>(driver->OpenDevice(path));
response.Push(device::NvStatus::Success);
@ -31,7 +30,7 @@ namespace skyline::service::nvdrv {
// Strip the permissions from the command leaving only the ID
cmd &= 0xFFFF;
std::optional<kernel::ipc::IpcBuffer> buffer{std::nullopt};
span<u8> buffer{};
if (request.inputBuf.empty() || request.outputBuf.empty()) {
if (!request.inputBuf.empty())
buffer = request.inputBuf.at(0);
@ -39,13 +38,16 @@ namespace skyline::service::nvdrv {
buffer = request.outputBuf.at(0);
else
throw exception("No IOCTL Buffers");
} else if (request.inputBuf.at(0).address == request.outputBuf.at(0).address) {
buffer = request.inputBuf.at(0);
} else if (request.inputBuf[0].data() == request.outputBuf[0].data()) {
if (request.inputBuf[0].size() >= request.outputBuf[0].size())
buffer = request.inputBuf[0];
else
buffer = request.outputBuf[0];
} else {
throw exception("IOCTL Input Buffer (0x{:X}) != Output Buffer (0x{:X})", request.inputBuf[0].address, request.outputBuf[0].address);
throw exception("IOCTL Input Buffer (0x{:X}) != Output Buffer (0x{:X})", fmt::ptr(request.inputBuf[0].data()), fmt::ptr(request.outputBuf[0].data()));
}
response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl, std::span<u8>(reinterpret_cast<u8 *>(buffer->address), buffer->size), {}));
response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl, buffer, {}));
return {};
}
@ -101,10 +103,16 @@ namespace skyline::service::nvdrv {
if (request.inputBuf.size() < 2 || request.outputBuf.empty())
throw exception("Inadequate amount of buffers for IOCTL2: I - {}, O - {}", request.inputBuf.size(), request.outputBuf.size());
else if (request.inputBuf[0].address != request.outputBuf[0].address)
throw exception("IOCTL2 Input Buffer (0x{:X}) != Output Buffer (0x{:X}) [Input Buffer #2: 0x{:X}]", request.inputBuf[0].address, request.outputBuf[0].address, request.inputBuf[1].address);
else if (request.inputBuf[0].data() != request.outputBuf[0].data())
throw exception("IOCTL2 Input Buffer (0x{:X}) != Output Buffer (0x{:X}) [Input Buffer #2: 0x{:X}]", fmt::ptr(request.inputBuf[0].data()), fmt::ptr(request.outputBuf[0].data()), fmt::ptr(request.inputBuf[1].data()));
response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl2, std::span<u8>(reinterpret_cast<u8 *>(request.inputBuf[0].address), request.inputBuf[0].size), std::span<u8>(reinterpret_cast<u8 *>(request.inputBuf[1].address), request.inputBuf[1].size)));
span<u8> buffer{};
if (request.inputBuf[0].size() >= request.outputBuf[0].size())
buffer = request.inputBuf[0];
else
buffer = request.outputBuf[0];
response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl2, buffer, request.inputBuf[1]));
return {};
}
@ -119,10 +127,16 @@ namespace skyline::service::nvdrv {
if (request.inputBuf.empty() || request.outputBuf.size() < 2)
throw exception("Inadequate amount of buffers for IOCTL3: I - {}, O - {}", request.inputBuf.size(), request.outputBuf.size());
else if (request.inputBuf[0].address != request.outputBuf[0].address)
throw exception("IOCTL3 Input Buffer (0x{:X}) != Output Buffer (0x{:X}) [Output Buffer #2: 0x{:X}]", request.inputBuf[0].address, request.outputBuf[0].address, request.outputBuf[1].address);
else if (request.inputBuf[0].data() != request.outputBuf[0].data())
throw exception("IOCTL3 Input Buffer (0x{:X}) != Output Buffer (0x{:X}) [Output Buffer #2: 0x{:X}]", fmt::ptr(request.inputBuf[0].data()), fmt::ptr(request.outputBuf[0].data()), fmt::ptr(request.outputBuf[1].data()));
response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl3, std::span<u8>(reinterpret_cast<u8 *>(request.inputBuf[0].address), request.inputBuf[0].size), std::span<u8>(reinterpret_cast<u8 *>(request.outputBuf[1].address), request.outputBuf[1].size)));
span<u8> buffer{};
if (request.inputBuf[0].size() >= request.outputBuf[0].size())
buffer = request.inputBuf[0];
else
buffer = request.outputBuf[0];
response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl3, buffer, request.outputBuf[1]));
return {};
}

View File

@ -17,7 +17,7 @@ namespace skyline::service::nvdrv::device {
return name;
}
NvStatus NvDevice::HandleIoctl(u32 cmd, IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvDevice::HandleIoctl(u32 cmd, IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
std::string_view typeString{[type] {
switch (type) {
case IoctlType::Ioctl:
@ -29,7 +29,7 @@ namespace skyline::service::nvdrv::device {
}
}()};
std::pair<std::function<NvStatus(IoctlType, std::span<u8>, std::span<u8>)>, std::string_view> function;
std::pair<std::function<NvStatus(IoctlType, span<u8>, span<u8>)>, std::string_view> function;
try {
function = GetIoctlFunction(cmd);
state.logger->Debug("{} @ {}: {}", typeString, GetName(), function.second);

View File

@ -8,11 +8,11 @@
#include <kernel/ipc.h>
#include <kernel/types/KEvent.h>
#define NVFUNC(id, Class, Function) std::pair<u32, std::pair<std::function<NvStatus(Class*, IoctlType, std::span<u8>, std::span<u8>)>, std::string_view>>{id, {&Class::Function, #Function}}
#define NVFUNC(id, Class, Function) std::pair<u32, std::pair<std::function<NvStatus(Class*, IoctlType, span<u8>, span<u8>)>, std::string_view>>{id, {&Class::Function, #Function}}
#define NVDEVICE_DECL_AUTO(name, value) decltype(value) name = value
#define NVDEVICE_DECL(...) \
NVDEVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \
std::pair<std::function<NvStatus(IoctlType, std::span<u8>, std::span<u8>)>, std::string_view> GetIoctlFunction(u32 id) { \
std::pair<std::function<NvStatus(IoctlType, span<u8>, span<u8>)>, std::string_view> GetIoctlFunction(u32 id) { \
auto& function = functions.at(id); \
return std::make_pair(std::bind(function.first, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), function.second); \
}
@ -73,7 +73,7 @@ namespace skyline::service::nvdrv::device {
virtual ~NvDevice() = default;
virtual std::pair<std::function<NvStatus(IoctlType, std::span<u8>, std::span<u8>)>, std::string_view> GetIoctlFunction(u32 id) = 0;
virtual std::pair<std::function<NvStatus(IoctlType, span<u8>, span<u8>)>, std::string_view> GetIoctlFunction(u32 id) = 0;
/**
* @return The name of the class
@ -85,7 +85,7 @@ namespace skyline::service::nvdrv::device {
* @brief This handles IOCTL calls for devices
* @param cmd The IOCTL command that was called
*/
NvStatus HandleIoctl(u32 cmd, IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus HandleIoctl(u32 cmd, IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
inline virtual std::shared_ptr<kernel::type::KEvent> QueryEvent(u32 eventId) {
return nullptr;

View File

@ -11,11 +11,11 @@
namespace skyline::service::nvdrv::device {
NvHostAsGpu::NvHostAsGpu(const DeviceState &state) : NvDevice(state) {}
NvStatus NvHostAsGpu::BindChannel(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostAsGpu::BindChannel(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostAsGpu::AllocSpace(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostAsGpu::AllocSpace(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 pages; // In
u32 pageSize; // In
@ -25,7 +25,7 @@ namespace skyline::service::nvdrv::device {
u64 offset; // InOut
u64 align; // In
};
} region = util::As<Data>(buffer);
} region = buffer.as<Data>();
u64 size = static_cast<u64>(region.pages) * static_cast<u64>(region.pageSize);
@ -42,8 +42,8 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success;
}
NvStatus NvHostAsGpu::UnmapBuffer(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
u64 offset{util::As<u64>(buffer)};
NvStatus NvHostAsGpu::UnmapBuffer(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
u64 offset{buffer.as<u64>()};
if (!state.gpu->memoryManager.Unmap(offset))
state.logger->Warn("Failed to unmap chunk at 0x{:X}", offset);
@ -51,7 +51,7 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success;
}
NvStatus NvHostAsGpu::Modify(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostAsGpu::Modify(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 flags; // In
u32 kind; // In
@ -60,7 +60,7 @@ namespace skyline::service::nvdrv::device {
u64 bufferOffset; // In
u64 mappingSize; // In
u64 offset; // InOut
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
try {
auto driver = nvdrv::driver.lock();
@ -87,7 +87,7 @@ namespace skyline::service::nvdrv::device {
}
}
NvStatus NvHostAsGpu::GetVaRegions(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostAsGpu::GetVaRegions(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
/*
struct Data {
u64 _pad0_;
@ -100,12 +100,12 @@ namespace skyline::service::nvdrv::device {
u32 pad;
u64 pages;
} regions[2]; // Out
} &regionInfo = util::As<Data>(buffer);
} &regionInfo = buffer.as<Data>();
*/
return NvStatus::Success;
}
NvStatus NvHostAsGpu::AllocAsEx(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostAsGpu::AllocAsEx(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
/*
struct Data {
u32 bigPageSize; // In
@ -115,12 +115,12 @@ namespace skyline::service::nvdrv::device {
u64 vaRangeStart; // In
u64 vaRangeEnd; // In
u64 vaRangeSplit; // In
} addressSpace = util::As<Data>(buffer);
} addressSpace = buffer.as<Data>();
*/
return NvStatus::Success;
}
NvStatus NvHostAsGpu::Remap(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostAsGpu::Remap(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Entry {
u16 flags; // In
u16 kind; // In
@ -132,7 +132,7 @@ namespace skyline::service::nvdrv::device {
constexpr u32 MinAlignmentShift{0x10}; // This shift is applied to all addresses passed to Remap
auto entries{util::AsSpan<Entry>(buffer)};
auto entries{buffer.cast<Entry>()};
for (auto entry : entries) {
try {
auto driver = nvdrv::driver.lock();

View File

@ -16,37 +16,37 @@ namespace skyline::service::nvdrv::device {
/**
* @brief This binds a channel to the address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_BIND_CHANNEL)
*/
NvStatus BindChannel(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus BindChannel(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This reserves a region in the GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_ALLOC_SPACE)
*/
NvStatus AllocSpace(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus AllocSpace(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This unmaps a region in the GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_UNMAP_BUFFER)
*/
NvStatus UnmapBuffer(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus UnmapBuffer(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This maps a region in the GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_MODIFY)
*/
NvStatus Modify(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus Modify(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This returns the application's GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_GET_VA_REGIONS)
*/
NvStatus GetVaRegions(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus GetVaRegions(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This initializes the application's GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_ALLOC_AS_EX)
*/
NvStatus AllocAsEx(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus AllocAsEx(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Remaps a region of the GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_REMAP)
*/
NvStatus Remap(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus Remap(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
NVDEVICE_DECL(
NVFUNC(0x4101, NvHostAsGpu, BindChannel),

View File

@ -16,15 +16,15 @@ namespace skyline::service::nvdrv::device {
channelFence.UpdateValue(hostSyncpoint);
}
NvStatus NvHostChannel::SetNvmapFd(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostChannel::SetNvmapFd(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::SetSubmitTimeout(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostChannel::SetSubmitTimeout(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::SubmitGpfifo(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostChannel::SubmitGpfifo(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u64 address; // In
u32 numEntries; // In
@ -41,7 +41,7 @@ namespace skyline::service::nvdrv::device {
u32 raw;
} flags; // In
Fence fence; // InOut
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
auto driver = nvdrv::driver.lock();
auto &hostSyncpoint = driver->hostSyncpoint;
@ -54,7 +54,7 @@ namespace skyline::service::nvdrv::device {
throw exception("Waiting on a fence through SubmitGpfifo is unimplemented");
}
state.gpu->gpfifo.Push(std::span(state.process->GetPointer<gpu::gpfifo::GpEntry>(data.address), data.numEntries));
state.gpu->gpfifo.Push(span(state.process->GetPointer<gpu::gpfifo::GpEntry>(data.address), data.numEntries));
data.fence.id = channelFence.id;
@ -69,20 +69,20 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success;
}
NvStatus NvHostChannel::AllocObjCtx(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostChannel::AllocObjCtx(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::ZcullBind(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostChannel::ZcullBind(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::SetErrorNotifier(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostChannel::SetErrorNotifier(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::SetPriority(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
switch (util::As<NvChannelPriority>(buffer)) {
NvStatus NvHostChannel::SetPriority(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
switch (buffer.as<NvChannelPriority>()) {
case NvChannelPriority::Low:
timeslice = 1300;
break;
@ -97,14 +97,14 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success;
}
NvStatus NvHostChannel::AllocGpfifoEx2(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostChannel::AllocGpfifoEx2(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 numEntries; // In
u32 numJobs; // In
u32 flags; // In
Fence fence; // Out
u32 reserved[3]; // In
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
auto driver = nvdrv::driver.lock();
channelFence.UpdateValue(driver->hostSyncpoint);
@ -113,7 +113,7 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success;
}
NvStatus NvHostChannel::SetUserData(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostChannel::SetUserData(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}

View File

@ -30,47 +30,47 @@ namespace skyline::service::nvdrv::device {
/**
* @brief This sets the nvmap file descriptor (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD)
*/
NvStatus SetNvmapFd(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus SetNvmapFd(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This sets the timeout for the channel (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_SET_SUBMIT_TIMEOUT)
*/
NvStatus SetSubmitTimeout(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus SetSubmitTimeout(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This submits a command to the GPFIFO (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO)
*/
NvStatus SubmitGpfifo(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus SubmitGpfifo(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This allocates a graphic context object (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX)
*/
NvStatus AllocObjCtx(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus AllocObjCtx(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This initializes the error notifier for this channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ZCULL_BIND)
*/
NvStatus ZcullBind(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus ZcullBind(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This initializes the error notifier for this channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER)
*/
NvStatus SetErrorNotifier(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus SetErrorNotifier(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This sets the priority of the channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_PRIORITY)
*/
NvStatus SetPriority(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus SetPriority(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This allocates a GPFIFO entry (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2)
*/
NvStatus AllocGpfifoEx2(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus AllocGpfifoEx2(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This sets the user specific data (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_USER_DATA)
*/
NvStatus SetUserData(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus SetUserData(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
std::shared_ptr<type::KEvent> QueryEvent(u32 eventId);

View File

@ -72,12 +72,12 @@ namespace skyline::service::nvdrv::device {
throw exception("Failed to find a free nvhost event!");
}
NvStatus NvHostCtrl::EventWaitImpl(std::span<u8> buffer, bool async) {
NvStatus NvHostCtrl::EventWaitImpl(span<u8> buffer, bool async) {
struct Data {
Fence fence; // In
u32 timeout; // In
EventValue value; // InOut
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
if (data.fence.id >= constant::MaxHwSyncpointCount)
return NvStatus::BadValue;
@ -135,12 +135,12 @@ namespace skyline::service::nvdrv::device {
}
}
NvStatus NvHostCtrl::GetConfig(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostCtrl::GetConfig(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::BadValue;
}
NvStatus NvHostCtrl::EventSignal(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
auto userEventId{util::As<u32>(buffer)};
NvStatus NvHostCtrl::EventSignal(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
auto userEventId{buffer.as<u32>()};
state.logger->Debug("Signalling nvhost event: {}", userEventId);
if (userEventId >= constant::NvHostEventCount || !events.at(userEventId))
@ -163,16 +163,16 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success;
}
NvStatus NvHostCtrl::EventWait(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostCtrl::EventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return EventWaitImpl(buffer, false);
}
NvStatus NvHostCtrl::EventWaitAsync(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostCtrl::EventWaitAsync(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return EventWaitImpl(buffer, true);
}
NvStatus NvHostCtrl::EventRegister(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
auto userEventId{util::As<u32>(buffer)};
NvStatus NvHostCtrl::EventRegister(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
auto userEventId{buffer.as<u32>()};
state.logger->Debug("Registering nvhost event: {}", userEventId);
auto &event = events.at(userEventId);

View File

@ -87,7 +87,7 @@ namespace skyline {
*/
u32 FindFreeEvent(u32 syncpointId);
NvStatus EventWaitImpl(std::span<u8> buffer, bool async);
NvStatus EventWaitImpl(span<u8> buffer, bool async);
public:
NvHostCtrl(const DeviceState &state);
@ -95,27 +95,27 @@ namespace skyline {
/**
* @brief This gets the value of an nvdrv setting, it returns an error code on production switches (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_GET_CONFIG)
*/
NvStatus GetConfig(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus GetConfig(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This signals an NvHost event (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_SIGNAL)
*/
NvStatus EventSignal(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus EventSignal(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This synchronously waits on an NvHost event (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_WAIT)
*/
NvStatus EventWait(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus EventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This asynchronously waits on an NvHost event (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_WAIT_ASYNC)
*/
NvStatus EventWaitAsync(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus EventWaitAsync(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This registers an NvHost event (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_REGISTER)
*/
NvStatus EventRegister(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus EventRegister(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
std::shared_ptr<type::KEvent> QueryEvent(u32 eventId);

View File

@ -7,12 +7,12 @@
namespace skyline::service::nvdrv::device {
NvHostCtrlGpu::NvHostCtrlGpu(const DeviceState &state) : errorNotifierEvent(std::make_shared<type::KEvent>(state)), unknownEvent(std::make_shared<type::KEvent>(state)), NvDevice(state) {}
NvStatus NvHostCtrlGpu::ZCullGetCtxSize(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
util::As<u32>(buffer) = 0x1;
NvStatus NvHostCtrlGpu::ZCullGetCtxSize(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
buffer.as<u32>() = 0x1;
return NvStatus::Success;
}
NvStatus NvHostCtrlGpu::ZCullGetInfo(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostCtrlGpu::ZCullGetInfo(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct ZCullInfo {
u32 widthAlignPixels{0x20};
u32 heightAlignPixels{0x20};
@ -26,11 +26,11 @@ namespace skyline::service::nvdrv::device {
u32 subregionCount{0x10};
} zCullInfo;
util::As<ZCullInfo>(buffer) = zCullInfo;
buffer.as<ZCullInfo>() = zCullInfo;
return NvStatus::Success;
}
NvStatus NvHostCtrlGpu::GetCharacteristics(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostCtrlGpu::GetCharacteristics(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct GpuCharacteristics {
u32 arch{0x120}; // NVGPU_GPU_ARCH_GM200
u32 impl{0xB}; // 0xB (NVGPU_GPU_IMPL_GM20B) or 0xE (NVGPU_GPU_IMPL_GM20B_B)
@ -73,7 +73,7 @@ namespace skyline::service::nvdrv::device {
u64 gpuCharacteristicsBufSize; // InOut
u64 gpuCharacteristicsBufAddr; // In
GpuCharacteristics gpuCharacteristics; // Out
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
if (data.gpuCharacteristicsBufSize < sizeof(GpuCharacteristics))
return NvStatus::InvalidSize;
@ -84,12 +84,12 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success;
}
NvStatus NvHostCtrlGpu::GetTpcMasks(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostCtrlGpu::GetTpcMasks(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 maskBufSize; // In
u32 reserved[3]; // In
u64 maskBuf; // Out
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
if (data.maskBufSize)
data.maskBuf = 0x3;
@ -97,12 +97,12 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success;
}
NvStatus NvHostCtrlGpu::GetActiveSlotMask(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvHostCtrlGpu::GetActiveSlotMask(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 slot{0x07}; // Out
u32 mask{0x01}; // Out
} data;
util::As<Data>(buffer) = data;
buffer.as<Data>() = data;
return NvStatus::Success;
}

View File

@ -20,27 +20,27 @@ namespace skyline::service::nvdrv::device {
/**
* @brief This returns a u32 GPU ZCULL Context Size (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZCULL_GET_CTX_SIZE)
*/
NvStatus ZCullGetCtxSize(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus ZCullGetCtxSize(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This returns a the GPU ZCULL Information (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZCULL_GET_INFO)
*/
NvStatus ZCullGetInfo(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus ZCullGetInfo(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This returns a struct with certain GPU characteristics (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_GET_CHARACTERISTICS)
*/
NvStatus GetCharacteristics(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus GetCharacteristics(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This returns the TPC mask value for each GPC (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_GET_TPC_MASKS)
*/
NvStatus GetTpcMasks(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus GetTpcMasks(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This returns the mask value for a ZBC slot (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZBC_GET_ACTIVE_SLOT_MASK)
*/
NvStatus GetActiveSlotMask(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus GetActiveSlotMask(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
std::shared_ptr<type::KEvent> QueryEvent(u32 eventId);

View File

@ -9,11 +9,11 @@ namespace skyline::service::nvdrv::device {
NvMap::NvMap(const DeviceState &state) : NvDevice(state) {}
NvStatus NvMap::Create(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvMap::Create(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 size; // In
u32 handle; // Out
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
handleTable[handleIndex] = std::make_shared<NvMapObject>(idIndex++, data.size);
data.handle = handleIndex++;
@ -22,11 +22,11 @@ namespace skyline::service::nvdrv::device {
return NvStatus::Success;
}
NvStatus NvMap::FromId(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvMap::FromId(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 id; // In
u32 handle; // Out
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
for (const auto &object : handleTable) {
if (object.second->id == data.id) {
@ -40,7 +40,7 @@ namespace skyline::service::nvdrv::device {
return NvStatus::BadValue;
}
NvStatus NvMap::Alloc(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvMap::Alloc(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 handle; // In
u32 heapMask; // In
@ -49,7 +49,7 @@ namespace skyline::service::nvdrv::device {
u8 kind; // In
u8 _pad0_[7];
u64 address; // InOut
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
try {
auto &object = handleTable.at(data.handle);
@ -68,14 +68,14 @@ namespace skyline::service::nvdrv::device {
}
}
NvStatus NvMap::Free(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvMap::Free(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 handle; // In
u32 _pad0_;
u64 address; // Out
u32 size; // Out
u32 flags; // Out
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
try {
const auto &object = handleTable.at(data.handle);
@ -98,13 +98,13 @@ namespace skyline::service::nvdrv::device {
}
}
NvStatus NvMap::Param(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvMap::Param(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
enum class Parameter : u32 { Size = 1, Alignment = 2, Base = 3, HeapMask = 4, Kind = 5, Compr = 6 }; // https://android.googlesource.com/kernel/tegra/+/refs/heads/android-tegra-flounder-3.10-marshmallow/include/linux/nvmap.h#102
struct Data {
u32 handle; // In
Parameter parameter; // In
u32 result; // Out
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
try {
auto &object = handleTable.at(data.handle);
@ -143,11 +143,11 @@ namespace skyline::service::nvdrv::device {
}
}
NvStatus NvMap::GetId(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer) {
NvStatus NvMap::GetId(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 id; // Out
u32 handle; // In
} &data = util::As<Data>(buffer);
} &data = buffer.as<Data>();
try {
data.id = handleTable.at(data.handle)->id;

View File

@ -44,32 +44,32 @@ namespace skyline::service::nvdrv::device {
/**
* @brief This creates an NvMapObject and returns an handle to it (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_CREATE)
*/
NvStatus Create(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus Create(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This returns the handle of an NvMapObject from it's ID (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_FROM_ID)
*/
NvStatus FromId(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus FromId(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This allocates memory for an NvMapObject (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_ALLOC)
*/
NvStatus Alloc(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus Alloc(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This frees previously allocated memory (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_FREE)
*/
NvStatus Free(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus Free(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This returns a particular parameter from an NvMapObject (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_PARAM)
*/
NvStatus Param(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus Param(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief This returns the ID of an NvMapObject from it's handle (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_GET_ID)
*/
NvStatus GetId(IoctlType type, std::span<u8> buffer, std::span<u8> inlineBuffer);
NvStatus GetId(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
NVDEVICE_DECL(
NVFUNC(0x0101, NvMap, Create),

View File

@ -11,7 +11,7 @@
namespace skyline::service::nvdrv {
Driver::Driver(const DeviceState &state) : state(state), hostSyncpoint(state) {}
u32 Driver::OpenDevice(const std::string &path) {
u32 Driver::OpenDevice(std::string_view path) {
state.logger->Debug("Opening NVDRV device ({}): {}", fdIndex, path);
switch (util::Hash(path)) {

View File

@ -46,7 +46,7 @@ namespace skyline::service::nvdrv {
* @param path The path of the device to open an FD to
* @return The file descriptor to the device
*/
u32 OpenDevice(const std::string &path);
u32 OpenDevice(std::string_view path);
/**
* @brief Returns a particular device with a specific FD

View File

@ -40,7 +40,7 @@ namespace skyline::service::pl {
*pointer++ = font.length ^ SharedFontKey;
font.offset = reinterpret_cast<u64>(pointer) - fontSharedMem->kernel.address;
memcpy(pointer, font.data, font.length);
std::memcpy(pointer, font.data, font.length);
pointer = reinterpret_cast<u32 *>(reinterpret_cast<u64>(pointer) + font.length);
}
}

View File

@ -7,7 +7,7 @@
namespace skyline::service::settings {
ISettingsServer::ISettingsServer(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
constexpr std::array<u64, constant::NewLanguageCodeListSize> LanguageCodeList = {
constexpr std::array<u64, constant::NewLanguageCodeListSize> LanguageCodeList{
util::MakeMagic<u64>("ja"),
util::MakeMagic<u64>("en-US"),
util::MakeMagic<u64>("fr"),
@ -28,8 +28,7 @@ namespace skyline::service::settings {
};
Result ISettingsServer::GetAvailableLanguageCodes(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
state.process->WriteMemory(LanguageCodeList.data(), request.outputBuf.at(0).address, constant::OldLanguageCodeListSize * sizeof(u64));
request.outputBuf.at(0).copy_from(span(LanguageCodeList).first(constant::OldLanguageCodeListSize));
response.Push<i32>(constant::OldLanguageCodeListSize);
return {};
}
@ -40,8 +39,7 @@ namespace skyline::service::settings {
}
Result ISettingsServer::GetAvailableLanguageCodes2(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
state.process->WriteMemory(LanguageCodeList.data(), request.outputBuf.at(0).address, constant::NewLanguageCodeListSize * sizeof(u64));
request.outputBuf.at(0).copy_from(LanguageCodeList);
response.Push<i32>(constant::NewLanguageCodeListSize);
return {};
}

View File

@ -8,8 +8,7 @@ namespace skyline::service::settings {
ISystemSettingsServer::ISystemSettingsServer(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
Result ISystemSettingsServer::GetFirmwareVersion(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
SysVerTitle title{.major=9, .minor=0, .micro=0, .revMajor=4, .revMinor=0, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
state.process->WriteMemory(title, request.outputBuf.at(0).address);
request.outputBuf.at(0).as<SysVerTitle>() = {.major=9, .minor=0, .micro=0, .revMajor=4, .revMinor=0, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
return {};
}
}