mirror of
https://github.com/Atmosphere-NX/Atmosphere-libs.git
synced 2025-06-21 19:12:42 +02:00
203 lines
9.1 KiB
C++
203 lines
9.1 KiB
C++
/*
|
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#pragma once
|
|
#include <vapours.hpp>
|
|
#include <mesosphere/svc/kern_svc_results.hpp>
|
|
#include <mesosphere/kern_select_userspace_memory_access.hpp>
|
|
|
|
namespace ams::kern::svc {
|
|
|
|
namespace impl {
|
|
|
|
/* TODO: C++20
|
|
template<typename T>
|
|
concept Pointer = std::is_pointer<T>::value;
|
|
|
|
template<typename T>
|
|
concept NonConstPointer = Pointer<T> && !std::is_const<typename std::remove_pointer<T>::type>::value;
|
|
|
|
template<typename T>
|
|
concept ConstPointer = Pointer<T> && std::is_const<typename std::remove_pointer<T>::type>::value;
|
|
|
|
template<typename T, size_t N>
|
|
concept AlignedNPointer = Pointer<T> && alignof(typename std::remove_pointer<T>::type) >= N && util::IsAligned(sizeof(typename std::remove_pointer<T>::type), N);
|
|
|
|
template<typename T>
|
|
concept Aligned8Pointer = AlignedNPointer<T, sizeof(u8)>;
|
|
|
|
template<typename T>
|
|
concept Aligned16Pointer = AlignedNPointer<T, sizeof(u16)> && Aligned8<T>;
|
|
|
|
template<typename T>
|
|
concept Aligned32Pointer = AlignedNPointer<T, sizeof(u32)> && Aligned16<T>;
|
|
|
|
template<typename T>
|
|
concept Aligned64Pointer = AlignedNPointer<T, sizeof(u64)> && Aligned32<T>;
|
|
*/
|
|
|
|
template<typename T>
|
|
constexpr inline bool IsPointer = std::is_pointer<T>::value;
|
|
|
|
template<typename T>
|
|
constexpr inline bool IsConstPointer = IsPointer<T> && std::is_const<typename std::remove_pointer<T>::type>::value;
|
|
|
|
template<typename T>
|
|
constexpr inline bool IsNonConstPointer = IsPointer<T> && !std::is_const<typename std::remove_pointer<T>::type>::value;
|
|
|
|
template<typename T, size_t N>
|
|
constexpr inline bool IsAlignedNPointer = IsPointer<T> && alignof(typename std::remove_pointer<T>::type) >= N && util::IsAligned(sizeof(typename std::remove_pointer<T>::type), N);
|
|
|
|
template<typename _T, typename = void> /* requires Aligned8Pointer<_T> */
|
|
class KUserPointerImplTraits {
|
|
static_assert(IsAlignedNPointer<_T, sizeof(u8)>);
|
|
public:
|
|
using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type;
|
|
public:
|
|
static Result CopyFromUserspace(void *dst, const void *src, size_t size) {
|
|
R_UNLESS(UserspaceAccess::CopyMemoryFromUser(dst, src, size), svc::ResultInvalidPointer());
|
|
return ResultSuccess();
|
|
}
|
|
|
|
static Result CopyToUserspace(void *dst, const void *src, size_t size) {
|
|
R_UNLESS(UserspaceAccess::CopyMemoryToUser(dst, src, size), svc::ResultInvalidPointer());
|
|
return ResultSuccess();
|
|
}
|
|
};
|
|
|
|
template<typename _T> /* requires Aligned32Pointer<_T> */
|
|
class KUserPointerImplTraits<_T, typename std::enable_if<IsAlignedNPointer<_T, sizeof(u32)> && !IsAlignedNPointer<_T, sizeof(u64)>>::type> {
|
|
static_assert(IsAlignedNPointer<_T, sizeof(u32)>);
|
|
public:
|
|
using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type;
|
|
public:
|
|
static Result CopyFromUserspace(void *dst, const void *src, size_t size) {
|
|
R_UNLESS(UserspaceAccess::CopyMemoryFromUserAligned32Bit(dst, src, size), svc::ResultInvalidPointer());
|
|
return ResultSuccess();
|
|
}
|
|
|
|
static Result CopyToUserspace(void *dst, const void *src, size_t size) {
|
|
R_UNLESS(UserspaceAccess::CopyMemoryToUserAligned32Bit(dst, src, size), svc::ResultInvalidPointer());
|
|
return ResultSuccess();
|
|
}
|
|
};
|
|
|
|
template<typename _T> /* requires Aligned64Pointer<_T> */
|
|
class KUserPointerImplTraits<_T, typename std::enable_if<IsAlignedNPointer<_T, sizeof(u64)>>::type> {
|
|
static_assert(IsAlignedNPointer<_T, sizeof(u64)>);
|
|
public:
|
|
using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type;
|
|
public:
|
|
static Result CopyFromUserspace(void *dst, const void *src, size_t size) {
|
|
R_UNLESS(UserspaceAccess::CopyMemoryFromUserAligned64Bit(dst, src, size), svc::ResultInvalidPointer());
|
|
return ResultSuccess();
|
|
}
|
|
|
|
static Result CopyToUserspace(void *dst, const void *src, size_t size) {
|
|
R_UNLESS(UserspaceAccess::CopyMemoryToUserAligned64Bit(dst, src, size), svc::ResultInvalidPointer());
|
|
return ResultSuccess();
|
|
}
|
|
};
|
|
|
|
template<typename _T> /* requires Aligned8Pointer<_T> */
|
|
class KUserPointerImpl : impl::KUserPointerTag {
|
|
private:
|
|
using Traits = KUserPointerImplTraits<_T>;
|
|
protected:
|
|
using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type;
|
|
private:
|
|
_T *ptr;
|
|
private:
|
|
Result CopyToImpl(void *p, size_t size) const {
|
|
return Traits::CopyFromUserspace(p, this->ptr, size);
|
|
}
|
|
|
|
Result CopyFromImpl(const void *p, size_t size) const {
|
|
return Traits::CopyToUserspace(this->ptr, p, size);
|
|
}
|
|
protected:
|
|
Result CopyTo(T *p) const { return this->CopyToImpl(p, sizeof(*p)); }
|
|
Result CopyFrom(const T *p) const { return this->CopyFromImpl(p, sizeof(*p)); }
|
|
|
|
Result CopyArrayElementTo(T *p, size_t index) const { return Traits::CopyFromUserspace(p, this->ptr + index, sizeof(*p)); }
|
|
Result CopyArrayElementFrom(const T *p, size_t index) const { return Traits::CopyToUserspace(this->ptr + index, p, sizeof(*p)); }
|
|
|
|
Result CopyArrayTo(T *arr, size_t count) const { return this->CopyToImpl(arr, sizeof(*arr) * count); }
|
|
Result CopyArrayFrom(const T *arr, size_t count) const { return this->CopyFromImpl(arr, sizeof(*arr) * count); }
|
|
|
|
constexpr bool IsNull() const { return this->ptr == nullptr; }
|
|
};
|
|
|
|
template<>
|
|
class KUserPointerImpl<const char *> : impl::KUserPointerTag {
|
|
private:
|
|
using Traits = KUserPointerImplTraits<const char *>;
|
|
protected:
|
|
using T = char;
|
|
private:
|
|
const char *ptr;
|
|
protected:
|
|
Result CopyStringTo(char *dst, size_t size) const {
|
|
static_assert(sizeof(char) == 1);
|
|
R_UNLESS(UserspaceAccess::CopyStringFromUser(dst, this->ptr, size) > 0, svc::ResultInvalidPointer());
|
|
return ResultSuccess();
|
|
}
|
|
|
|
Result CopyArrayElementTo(char *dst, size_t index) const {
|
|
return Traits::CopyFromUserspace(dst, this->ptr + index, sizeof(*dst));
|
|
}
|
|
|
|
constexpr bool IsNull() const { return this->ptr == nullptr; }
|
|
};
|
|
|
|
}
|
|
|
|
template<typename T, typename = void>
|
|
class KUserPointer;
|
|
|
|
template<typename T> /* requires impl::ConstPointer<T> */
|
|
struct KUserPointer<T, typename std::enable_if<impl::IsConstPointer<T>>::type> : public impl::KUserPointerImpl<T> {
|
|
public:
|
|
static constexpr bool IsInput = true;
|
|
public:
|
|
using impl::KUserPointerImpl<T>::CopyTo;
|
|
using impl::KUserPointerImpl<T>::CopyArrayElementTo;
|
|
using impl::KUserPointerImpl<T>::CopyArrayTo;
|
|
using impl::KUserPointerImpl<T>::IsNull;
|
|
};
|
|
|
|
template<typename T> /* requires impl::NonConstPointer<T> */
|
|
struct KUserPointer<T, typename std::enable_if<impl::IsNonConstPointer<T>>::type> : public impl::KUserPointerImpl<T> {
|
|
public:
|
|
static constexpr bool IsInput = false;
|
|
public:
|
|
using impl::KUserPointerImpl<T>::CopyFrom;
|
|
using impl::KUserPointerImpl<T>::CopyArrayElementFrom;
|
|
using impl::KUserPointerImpl<T>::CopyArrayFrom;
|
|
using impl::KUserPointerImpl<T>::IsNull;
|
|
};
|
|
|
|
template<>
|
|
struct KUserPointer<const char *> : public impl::KUserPointerImpl<const char *> {
|
|
public:
|
|
static constexpr bool IsInput = true;
|
|
public:
|
|
using impl::KUserPointerImpl<const char *>::CopyStringTo;
|
|
using impl::KUserPointerImpl<const char *>::CopyArrayElementTo;
|
|
using impl::KUserPointerImpl<const char *>::IsNull;
|
|
};
|
|
|
|
}
|