diff --git a/libraries/libvapours/include/vapours/util/util_bitpack.hpp b/libraries/libvapours/include/vapours/util/util_bitpack.hpp index ccec50e98..914d5b2d8 100644 --- a/libraries/libvapours/include/vapours/util/util_bitpack.hpp +++ b/libraries/libvapours/include/vapours/util/util_bitpack.hpp @@ -33,7 +33,11 @@ namespace ams::util { static_assert(0 < Count && Count <= BITSIZEOF(IntegralStorageType)); static_assert(Index + Count <= BITSIZEOF(IntegralStorageType)); - return ((IntegralStorageType(1) << Count) - 1) << Index; + if constexpr (Count == BITSIZEOF(IntegralStorageType)) { + return ~IntegralStorageType(0); + } else { + return ((IntegralStorageType(1) << Count) - 1) << Index; + } }(); public: template @@ -52,6 +56,8 @@ namespace ams::util { private: IntegralStorageType value; public: + constexpr ALWAYS_INLINE BitPack(IntegralStorageType v) : value(v) { /* ... */ } + constexpr ALWAYS_INLINE void Clear() { constexpr IntegralStorageType Zero = IntegralStorageType(0); this->value = Zero; @@ -79,9 +85,9 @@ namespace ams::util { using BitPack32 = impl::BitPack; using BitPack64 = impl::BitPack; - static_assert(std::is_pod::value); - static_assert(std::is_pod::value); - static_assert(std::is_pod::value); - static_assert(std::is_pod::value); + static_assert(std::is_trivially_destructible::value); + static_assert(std::is_trivially_destructible::value); + static_assert(std::is_trivially_destructible::value); + static_assert(std::is_trivially_destructible::value); } diff --git a/stratosphere/loader/source/ldr_capabilities.cpp b/stratosphere/loader/source/ldr_capabilities.cpp index bcb57d00c..3c86d7db0 100644 --- a/stratosphere/loader/source/ldr_capabilities.cpp +++ b/stratosphere/loader/source/ldr_capabilities.cpp @@ -34,63 +34,54 @@ namespace ams::ldr::caps { Empty = 32, }; - constexpr CapabilityId GetCapabilityId(u32 cap) { - return static_cast(__builtin_ctz(~cap)); + template + using CapabilityField = util::BitPack32::Field; + + #define DEFINE_CAPABILITY_FIELD(name, prev, ...) \ + using name = CapabilityField; \ + constexpr ALWAYS_INLINE typename name::Type Get##name() const { return this->Get(); } + + constexpr ALWAYS_INLINE CapabilityId GetCapabilityId(util::BitPack32 cap) { + using RawValue = CapabilityField<0, BITSIZEOF(u32)>; + return static_cast(__builtin_ctz(~cap.Get())); } - template - class Capability { - public: - static constexpr u32 ValueShift = static_cast(Id) + 1; - static constexpr u32 IdMask = (1u << (ValueShift - 1)) - 1; - private: - u32 value; - public: - Capability(u32 v) : value(v) { /* ... */ } - - CapabilityId GetId() const { - return Id; - } - - u32 GetValue() const { - return this->value >> ValueShift; - } - }; - #define CAPABILITY_CLASS_NAME(id) Capability##id -#define CAPABILITY_BASE_CLASS(id) Capability -#define DEFINE_CAPABILITY_CLASS(id, member_functions) \ - class CAPABILITY_CLASS_NAME(id) : public CAPABILITY_BASE_CLASS(id) { \ - public: \ - CAPABILITY_CLASS_NAME(id)(u32 v) : CAPABILITY_BASE_CLASS(id)(v) { /* ... */ } \ -\ - static CAPABILITY_CLASS_NAME(id) Decode(u32 v) { return CAPABILITY_CLASS_NAME(id)(v); } \ -\ - member_functions \ - } +#define DEFINE_CAPABILITY_CLASS(id, member_functions) \ + class CAPABILITY_CLASS_NAME(id) { \ + public: \ + static constexpr CapabilityId Id = CapabilityId::id; \ + using IdBits = CapabilityField<0, static_cast(Id) + 1>; \ + using RawValue = CapabilityField; \ + static constexpr u32 IdBitsValue = (static_cast(1) << static_cast(Id)) - 1; \ + private: \ + util::BitPack32 value; \ + private: \ + template \ + constexpr ALWAYS_INLINE typename FieldType::Type Get() const { return this->value.Get(); } \ + template \ + constexpr ALWAYS_INLINE void Set(typename FieldType::Type fv) { this->value.Set(fv); } \ + constexpr ALWAYS_INLINE u32 GetValue() const { return this->Get(); } \ + public: \ + constexpr ALWAYS_INLINE CAPABILITY_CLASS_NAME(id)(util::BitPack32 v) : value(v) { /* ... */ } \ + \ + static constexpr CAPABILITY_CLASS_NAME(id) Decode(util::BitPack32 v) { return CAPABILITY_CLASS_NAME(id)(v); } \ + \ + member_functions \ + }; \ + static_assert(std::is_trivially_destructible::value) /* Class definitions. */ DEFINE_CAPABILITY_CLASS(KernelFlags, - u32 GetMaximumThreadPriority() const { - return (this->GetValue() >> 0) & 0x3F; - } + DEFINE_CAPABILITY_FIELD(MaximumThreadPriority, IdBits, 6); + DEFINE_CAPABILITY_FIELD(MinimumThreadPriority, MaximumThreadPriority, 6); + DEFINE_CAPABILITY_FIELD(MinimumCoreId, MinimumThreadPriority, 8); + DEFINE_CAPABILITY_FIELD(MaximumCoreId, MinimumCoreId, 8); - u32 GetMinimumThreadPriority() const { - return (this->GetValue() >> 6) & 0x3F; - } - - u32 GetMinimumCoreId() const { - return (this->GetValue() >> 12) & 0xFF; - } - - u32 GetMaximumCoreId() const { - return (this->GetValue() >> 20) & 0xFF; - } - - bool IsValid(const u32 *kac, size_t kac_count) const { + bool IsValid(const util::BitPack32 *kac, size_t kac_count) const { for (size_t i = 0; i < kac_count; i++) { - if (GetCapabilityId(kac[i]) == this->GetId()) { + if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i]); if (this->GetMinimumThreadPriority() < restriction.GetMinimumThreadPriority() || @@ -113,17 +104,12 @@ namespace ams::ldr::caps { ); DEFINE_CAPABILITY_CLASS(SyscallMask, - u32 GetMask() const { - return (this->GetValue() >> 0) & 0xFFFFFF; - } + DEFINE_CAPABILITY_FIELD(Mask, IdBits, 24); + DEFINE_CAPABILITY_FIELD(Index, Mask, 3); - u32 GetIndex() const { - return (this->GetValue() >> 24) & 0x7; - } - - bool IsValid(const u32 *kac, size_t kac_count) const { + bool IsValid(const util::BitPack32 *kac, size_t kac_count) const { for (size_t i = 0; i < kac_count; i++) { - if (GetCapabilityId(kac[i]) == this->GetId()) { + if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i]); if (this->GetIndex() == restriction.GetIndex() && this->GetMask() == restriction.GetMask()) { @@ -136,18 +122,12 @@ namespace ams::ldr::caps { ); DEFINE_CAPABILITY_CLASS(MapRange, + DEFINE_CAPABILITY_FIELD(AddressSize, IdBits, 24); + DEFINE_CAPABILITY_FIELD(Flag, AddressSize, 1, bool); static constexpr size_t SizeMax = 0x100000; - u32 GetAddressSize() const { - return (this->GetValue() >> 0) & 0xFFFFFF; - } - - u32 GetFlag() const { - return (this->GetValue() >> 24) & 0x1; - } - - bool IsValid(const u32 next_cap, const u32 *kac, size_t kac_count) const { - if (GetCapabilityId(next_cap) != this->GetId()) { + bool IsValid(const util::BitPack32 next_cap, const util::BitPack32 *kac, size_t kac_count) const { + if (GetCapabilityId(next_cap) != Id) { return false; } @@ -160,9 +140,9 @@ namespace ams::ldr::caps { } for (size_t i = 0; i < kac_count; i++) { - if (GetCapabilityId(kac[i]) == this->GetId()) { + if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i++]); - if (i >= kac_count || GetCapabilityId(kac[i]) != this->GetId()) { + if (i >= kac_count || GetCapabilityId(kac[i]) != Id) { return false; } const auto restriction_next = Decode(kac[i]); @@ -186,13 +166,11 @@ namespace ams::ldr::caps { ); DEFINE_CAPABILITY_CLASS(MapPage, - u32 GetAddress() const { - return (this->GetValue() >> 0) & 0xFFFFFF; - } + DEFINE_CAPABILITY_FIELD(Address, IdBits, 24); - bool IsValid(const u32 *kac, size_t kac_count) const { + bool IsValid(const util::BitPack32 *kac, size_t kac_count) const { for (size_t i = 0; i < kac_count; i++) { - if (GetCapabilityId(kac[i]) == this->GetId()) { + if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i]); if (this->GetValue() == restriction.GetValue()) { @@ -205,19 +183,13 @@ namespace ams::ldr::caps { ); DEFINE_CAPABILITY_CLASS(InterruptPair, + DEFINE_CAPABILITY_FIELD(InterruptId0, IdBits, 10); + DEFINE_CAPABILITY_FIELD(InterruptId1, InterruptId0, 10); static constexpr u32 EmptyInterruptId = 0x3FF; - u32 GetInterruptId0() const { - return (this->GetValue() >> 0) & 0x3FF; - } - - u32 GetInterruptId1() const { - return (this->GetValue() >> 10) & 0x3FF; - } - - bool IsSingleIdValid(const u32 id, const u32 *kac, size_t kac_count) const { + bool IsSingleIdValid(const u32 id, const util::BitPack32 *kac, size_t kac_count) const { for (size_t i = 0; i < kac_count; i++) { - if (GetCapabilityId(kac[i]) == this->GetId()) { + if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i]); if (restriction.GetInterruptId0() == EmptyInterruptId && restriction.GetInterruptId1() == EmptyInterruptId) { @@ -232,19 +204,17 @@ namespace ams::ldr::caps { return false; } - bool IsValid(const u32 *kac, size_t kac_count) const { + bool IsValid(const util::BitPack32 *kac, size_t kac_count) const { return IsSingleIdValid(this->GetInterruptId0(), kac, kac_count) && IsSingleIdValid(this->GetInterruptId1(), kac, kac_count); } ); DEFINE_CAPABILITY_CLASS(ApplicationType, - u32 GetApplicationType() const { - return (this->GetValue() >> 0) & 0x3; - } + DEFINE_CAPABILITY_FIELD(ApplicationType, IdBits, 3); - bool IsValid(const u32 *kac, size_t kac_count) const { + bool IsValid(const util::BitPack32 *kac, size_t kac_count) const { for (size_t i = 0; i < kac_count; i++) { - if (GetCapabilityId(kac[i]) == this->GetId()) { + if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i]); return restriction.GetValue() == this->GetValue(); @@ -253,24 +223,20 @@ namespace ams::ldr::caps { return false; } - static constexpr u32 Encode(u32 app_type) { - return ((app_type & 3) << ValueShift) | IdMask; + static constexpr util::BitPack32 Encode(u32 app_type) { + util::BitPack32 encoded(IdBitsValue); + encoded.Set(app_type); + return encoded; } ); DEFINE_CAPABILITY_CLASS(KernelVersion, - u32 GetMinorVersion() const { - return (this->GetValue() >> 0) & 0xF; - } + DEFINE_CAPABILITY_FIELD(MinorVersion, IdBits, 4); + DEFINE_CAPABILITY_FIELD(MajorVersion, MinorVersion, 13); - u32 GetMajorVersion() const { - /* TODO: Are upper bits unused? */ - return (this->GetValue() >> 4) & 0x1FFF; - } - - bool IsValid(const u32 *kac, size_t kac_count) const { + bool IsValid(const util::BitPack32 *kac, size_t kac_count) const { for (size_t i = 0; i < kac_count; i++) { - if (GetCapabilityId(kac[i]) == this->GetId()) { + if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i]); return restriction.GetValue() == this->GetValue(); @@ -281,13 +247,11 @@ namespace ams::ldr::caps { ); DEFINE_CAPABILITY_CLASS(HandleTable, - u32 GetSize() const { - return (this->GetValue() >> 0) & 0x3FF; - } + DEFINE_CAPABILITY_FIELD(Size, IdBits, 10); - bool IsValid(const u32 *kac, size_t kac_count) const { + bool IsValid(const util::BitPack32 *kac, size_t kac_count) const { for (size_t i = 0; i < kac_count; i++) { - if (GetCapabilityId(kac[i]) == this->GetId()) { + if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i]); return this->GetSize() <= restriction.GetSize(); @@ -298,17 +262,12 @@ namespace ams::ldr::caps { ); DEFINE_CAPABILITY_CLASS(DebugFlags, - bool GetAllowDebug() const { - return (this->GetValue() >> 0) & 1; - } + DEFINE_CAPABILITY_FIELD(AllowDebug, IdBits, 1, bool); + DEFINE_CAPABILITY_FIELD(ForceDebug, AllowDebug, 1, bool); - bool GetForceDebug() const { - return (this->GetValue() >> 1) & 1; - } - - bool IsValid(const u32 *kac, size_t kac_count) const { + bool IsValid(const util::BitPack32 *kac, size_t kac_count) const { for (size_t i = 0; i < kac_count; i++) { - if (GetCapabilityId(kac[i]) == this->GetId()) { + if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i]); return (restriction.GetValue() & this->GetValue()) == this->GetValue(); @@ -317,9 +276,11 @@ namespace ams::ldr::caps { return false; } - static constexpr u32 Encode(bool allow_debug, bool force_debug) { - const u32 desc = (static_cast(force_debug) << 1) | (static_cast(allow_debug) << 0); - return (desc << ValueShift) | IdMask; + static constexpr util::BitPack32 Encode(bool allow_debug, bool force_debug) { + util::BitPack32 encoded(IdBitsValue); + encoded.Set(allow_debug); + encoded.Set(force_debug); + return encoded; } ); @@ -327,13 +288,13 @@ namespace ams::ldr::caps { /* Capabilities API. */ Result ValidateCapabilities(const void *acid_kac, size_t acid_kac_size, const void *aci_kac, size_t aci_kac_size) { - const u32 *acid_caps = reinterpret_cast(acid_kac); - const u32 *aci_caps = reinterpret_cast(aci_kac); + const util::BitPack32 *acid_caps = reinterpret_cast(acid_kac); + const util::BitPack32 *aci_caps = reinterpret_cast(aci_kac); const size_t num_acid_caps = acid_kac_size / sizeof(*acid_caps); const size_t num_aci_caps = aci_kac_size / sizeof(*aci_caps); for (size_t i = 0; i < num_aci_caps; i++) { - const u32 cur_cap = aci_caps[i]; + const auto cur_cap = aci_caps[i]; const auto id = GetCapabilityId(cur_cap); #define VALIDATE_CASE(id) \ @@ -368,12 +329,12 @@ namespace ams::ldr::caps { } u16 GetProgramInfoFlags(const void *kac, size_t kac_size) { - const u32 *caps = reinterpret_cast(kac); + const util::BitPack32 *caps = reinterpret_cast(kac); const size_t num_caps = kac_size / sizeof(*caps); u16 flags = 0; for (size_t i = 0; i < num_caps; i++) { - const u32 cur_cap = caps[i]; + const auto cur_cap = caps[i]; switch (GetCapabilityId(cur_cap)) { case CapabilityId::ApplicationType: @@ -398,11 +359,11 @@ namespace ams::ldr::caps { } void SetProgramInfoFlags(u16 flags, void *kac, size_t kac_size) { - u32 *caps = reinterpret_cast(kac); + util::BitPack32 *caps = reinterpret_cast(kac); const size_t num_caps = kac_size / sizeof(*caps); for (size_t i = 0; i < num_caps; i++) { - const u32 cur_cap = caps[i]; + const auto cur_cap = caps[i]; switch (GetCapabilityId(cur_cap)) { case CapabilityId::ApplicationType: caps[i] = CapabilityApplicationType::Encode(flags & ProgramInfoFlag_ApplicationTypeMask);