mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
loader: use BitPack for caps
This commit is contained in:
parent
38f942adf5
commit
0d8bde6079
2 changed files with 98 additions and 131 deletions
|
@ -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<size_t _Index, size_t _Count, typename T>
|
||||
|
@ -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<u32>;
|
||||
using BitPack64 = impl::BitPack<u64>;
|
||||
|
||||
static_assert(std::is_pod<BitPack8 >::value);
|
||||
static_assert(std::is_pod<BitPack16>::value);
|
||||
static_assert(std::is_pod<BitPack32>::value);
|
||||
static_assert(std::is_pod<BitPack64>::value);
|
||||
static_assert(std::is_trivially_destructible<BitPack8 >::value);
|
||||
static_assert(std::is_trivially_destructible<BitPack16>::value);
|
||||
static_assert(std::is_trivially_destructible<BitPack32>::value);
|
||||
static_assert(std::is_trivially_destructible<BitPack64>::value);
|
||||
|
||||
}
|
||||
|
|
|
@ -34,63 +34,54 @@ namespace ams::ldr::caps {
|
|||
Empty = 32,
|
||||
};
|
||||
|
||||
constexpr CapabilityId GetCapabilityId(u32 cap) {
|
||||
return static_cast<CapabilityId>(__builtin_ctz(~cap));
|
||||
template<size_t Index, size_t Count, typename T = u32>
|
||||
using CapabilityField = util::BitPack32::Field<Index, Count, T>;
|
||||
|
||||
#define DEFINE_CAPABILITY_FIELD(name, prev, ...) \
|
||||
using name = CapabilityField<prev::Next, __VA_ARGS__>; \
|
||||
constexpr ALWAYS_INLINE typename name::Type Get##name() const { return this->Get<name>(); }
|
||||
|
||||
constexpr ALWAYS_INLINE CapabilityId GetCapabilityId(util::BitPack32 cap) {
|
||||
using RawValue = CapabilityField<0, BITSIZEOF(u32)>;
|
||||
return static_cast<CapabilityId>(__builtin_ctz(~cap.Get<RawValue>()));
|
||||
}
|
||||
|
||||
template<CapabilityId Id>
|
||||
class Capability {
|
||||
public:
|
||||
static constexpr u32 ValueShift = static_cast<u32>(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<CapabilityId::id>
|
||||
|
||||
#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<size_t>(Id) + 1>; \
|
||||
using RawValue = CapabilityField<IdBits::Next, BITSIZEOF(u32) - IdBits::Next>; \
|
||||
static constexpr u32 IdBitsValue = (static_cast<u32>(1) << static_cast<size_t>(Id)) - 1; \
|
||||
private: \
|
||||
util::BitPack32 value; \
|
||||
private: \
|
||||
template<typename FieldType> \
|
||||
constexpr ALWAYS_INLINE typename FieldType::Type Get() const { return this->value.Get<FieldType>(); } \
|
||||
template<typename FieldType> \
|
||||
constexpr ALWAYS_INLINE void Set(typename FieldType::Type fv) { this->value.Set<FieldType>(fv); } \
|
||||
constexpr ALWAYS_INLINE u32 GetValue() const { return this->Get<RawValue>(); } \
|
||||
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<CAPABILITY_CLASS_NAME(id)>::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<ApplicationType>(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<u32>(force_debug) << 1) | (static_cast<u32>(allow_debug) << 0);
|
||||
return (desc << ValueShift) | IdMask;
|
||||
static constexpr util::BitPack32 Encode(bool allow_debug, bool force_debug) {
|
||||
util::BitPack32 encoded(IdBitsValue);
|
||||
encoded.Set<AllowDebug>(allow_debug);
|
||||
encoded.Set<ForceDebug>(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<const u32 *>(acid_kac);
|
||||
const u32 *aci_caps = reinterpret_cast<const u32 *>(aci_kac);
|
||||
const util::BitPack32 *acid_caps = reinterpret_cast<const util::BitPack32 *>(acid_kac);
|
||||
const util::BitPack32 *aci_caps = reinterpret_cast<const util::BitPack32 *>(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<const u32 *>(kac);
|
||||
const util::BitPack32 *caps = reinterpret_cast<const util::BitPack32 *>(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<u32 *>(kac);
|
||||
util::BitPack32 *caps = reinterpret_cast<util::BitPack32 *>(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);
|
||||
|
|
Loading…
Reference in a new issue