diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/kernel/k_capabilities.h | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/src/core/hle/kernel/k_capabilities.h b/src/core/hle/kernel/k_capabilities.h new file mode 100644 index 000000000..de766c811 --- /dev/null +++ b/src/core/hle/kernel/k_capabilities.h @@ -0,0 +1,295 @@ + +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <bitset> +#include <span> + +#include "common/bit_field.h" +#include "common/common_types.h" + +#include "core/hle/kernel/svc_types.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KPageTable; +class KernelCore; + +class KCapabilities { +public: + constexpr explicit KCapabilities() = default; + + Result InitializeForKip(std::span<const u32> kern_caps, KPageTable* page_table); + Result InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table); + + static Result CheckCapabilities(KernelCore& kernel, std::span<const u32> user_caps); + + constexpr u64 GetCoreMask() const { + return m_core_mask; + } + + constexpr u64 GetPhysicalCoreMask() const { + return m_phys_core_mask; + } + + constexpr u64 GetPriorityMask() const { + return m_priority_mask; + } + + constexpr s32 GetHandleTableSize() const { + return m_handle_table_size; + } + + constexpr const Svc::SvcAccessFlagSet& GetSvcPermissions() const { + return m_svc_access_flags; + } + + constexpr bool IsPermittedSvc(u32 id) const { + return (id < m_svc_access_flags.size()) && m_svc_access_flags[id]; + } + + constexpr bool IsPermittedInterrupt(u32 id) const { + return (id < m_irq_access_flags.size()) && m_irq_access_flags[id]; + } + + constexpr bool IsPermittedDebug() const { + return DebugFlags{m_debug_capabilities}.allow_debug.Value() != 0; + } + + constexpr bool CanForceDebug() const { + return DebugFlags{m_debug_capabilities}.force_debug.Value() != 0; + } + + constexpr u32 GetIntendedKernelMajorVersion() const { + return KernelVersion{m_intended_kernel_version}.major_version; + } + + constexpr u32 GetIntendedKernelMinorVersion() const { + return KernelVersion{m_intended_kernel_version}.minor_version; + } + +private: + static constexpr size_t InterruptIdCount = 0x400; + using InterruptFlagSet = std::bitset<InterruptIdCount>; + + enum class CapabilityType : u32 { + CorePriority = (1U << 3) - 1, + SyscallMask = (1U << 4) - 1, + MapRange = (1U << 6) - 1, + MapIoPage = (1U << 7) - 1, + MapRegion = (1U << 10) - 1, + InterruptPair = (1U << 11) - 1, + ProgramType = (1U << 13) - 1, + KernelVersion = (1U << 14) - 1, + HandleTable = (1U << 15) - 1, + DebugFlags = (1U << 16) - 1, + + Invalid = 0U, + Padding = ~0U, + }; + + using RawCapabilityValue = u32; + + static constexpr CapabilityType GetCapabilityType(const RawCapabilityValue value) { + return static_cast<CapabilityType>((~value & (value + 1)) - 1); + } + + static constexpr u32 GetCapabilityFlag(CapabilityType type) { + return static_cast<u32>(type) + 1; + } + + template <CapabilityType Type> + static constexpr inline u32 CapabilityFlag = static_cast<u32>(Type) + 1; + + template <CapabilityType Type> + static constexpr inline u32 CapabilityId = std::countr_zero(CapabilityFlag<Type>); + + union CorePriority { + static_assert(CapabilityId<CapabilityType::CorePriority> + 1 == 4); + + RawCapabilityValue raw; + BitField<0, 4, CapabilityType> id; + BitField<4, 6, u32> lowest_thread_priority; + BitField<10, 6, u32> highest_thread_priority; + BitField<16, 8, u32> minimum_core_id; + BitField<24, 8, u32> maximum_core_id; + }; + + union SyscallMask { + static_assert(CapabilityId<CapabilityType::SyscallMask> + 1 == 5); + + RawCapabilityValue raw; + BitField<0, 5, CapabilityType> id; + BitField<5, 24, u32> mask; + BitField<29, 3, u32> index; + }; + + // #undef MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES + static constexpr u64 PhysicalMapAllowedMask = (1ULL << 36) - 1; + + union MapRange { + static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7); + + RawCapabilityValue raw; + BitField<0, 7, CapabilityType> id; + BitField<7, 24, u32> address; + BitField<31, 1, u32> read_only; + }; + + union MapRangeSize { + static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7); + + RawCapabilityValue raw; + BitField<0, 7, CapabilityType> id; + BitField<7, 20, u32> pages; + BitField<27, 4, u32> reserved; + BitField<31, 1, u32> normal; + }; + + union MapIoPage { + static_assert(CapabilityId<CapabilityType::MapIoPage> + 1 == 8); + + RawCapabilityValue raw; + BitField<0, 8, CapabilityType> id; + BitField<8, 24, u32> address; + }; + + enum class RegionType : u32 { + NoMapping = 0, + KernelTraceBuffer = 1, + OnMemoryBootImage = 2, + DTB = 3, + }; + + union MapRegion { + static_assert(CapabilityId<CapabilityType::MapRegion> + 1 == 11); + + RawCapabilityValue raw; + BitField<0, 11, CapabilityType> id; + BitField<11, 6, RegionType> region0; + BitField<17, 1, u32> read_only0; + BitField<18, 6, RegionType> region1; + BitField<24, 1, u32> read_only1; + BitField<25, 6, RegionType> region2; + BitField<31, 1, u32> read_only2; + }; + + union InterruptPair { + static_assert(CapabilityId<CapabilityType::InterruptPair> + 1 == 12); + + RawCapabilityValue raw; + BitField<0, 12, CapabilityType> id; + BitField<12, 10, u32> interrupt_id0; + BitField<22, 10, u32> interrupt_id1; + }; + + union ProgramType { + static_assert(CapabilityId<CapabilityType::ProgramType> + 1 == 14); + + RawCapabilityValue raw; + BitField<0, 14, CapabilityType> id; + BitField<14, 3, u32> type; + BitField<17, 15, u32> reserved; + }; + + union KernelVersion { + static_assert(CapabilityId<CapabilityType::KernelVersion> + 1 == 15); + + RawCapabilityValue raw; + BitField<0, 15, CapabilityType> id; + BitField<15, 4, u32> major_version; + BitField<19, 13, u32> minor_version; + }; + + union HandleTable { + static_assert(CapabilityId<CapabilityType::HandleTable> + 1 == 16); + + RawCapabilityValue raw; + BitField<0, 16, CapabilityType> id; + BitField<16, 10, u32> size; + BitField<26, 6, u32> reserved; + }; + + union DebugFlags { + static_assert(CapabilityId<CapabilityType::DebugFlags> + 1 == 17); + + RawCapabilityValue raw; + BitField<0, 17, CapabilityType> id; + BitField<17, 1, u32> allow_debug; + BitField<18, 1, u32> force_debug; + BitField<19, 13, u32> reserved; + }; + + static_assert(sizeof(CorePriority) == 4); + static_assert(sizeof(SyscallMask) == 4); + static_assert(sizeof(MapRange) == 4); + static_assert(sizeof(MapRangeSize) == 4); + static_assert(sizeof(MapIoPage) == 4); + static_assert(sizeof(MapRegion) == 4); + static_assert(sizeof(InterruptPair) == 4); + static_assert(sizeof(ProgramType) == 4); + static_assert(sizeof(KernelVersion) == 4); + static_assert(sizeof(HandleTable) == 4); + static_assert(sizeof(DebugFlags) == 4); + + static constexpr u32 InitializeOnceFlags = + CapabilityFlag<CapabilityType::CorePriority> | CapabilityFlag<CapabilityType::ProgramType> | + CapabilityFlag<CapabilityType::KernelVersion> | + CapabilityFlag<CapabilityType::HandleTable> | CapabilityFlag<CapabilityType::DebugFlags>; + + static const u32 PaddingInterruptId = 0x3FF; + static_assert(PaddingInterruptId < InterruptIdCount); + +private: + constexpr bool SetSvcAllowed(u32 id) { + if (id < m_svc_access_flags.size()) [[likely]] { + m_svc_access_flags[id] = true; + return true; + } else { + return false; + } + } + + constexpr bool SetInterruptPermitted(u32 id) { + if (id < m_irq_access_flags.size()) [[likely]] { + m_irq_access_flags[id] = true; + return true; + } else { + return false; + } + } + + Result SetCorePriorityCapability(const u32 cap); + Result SetSyscallMaskCapability(const u32 cap, u32& set_svc); + Result MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table); + Result MapIoPage_(const u32 cap, KPageTable* page_table); + Result MapRegion_(const u32 cap, KPageTable* page_table); + Result SetInterruptPairCapability(const u32 cap); + Result SetProgramTypeCapability(const u32 cap); + Result SetKernelVersionCapability(const u32 cap); + Result SetHandleTableCapability(const u32 cap); + Result SetDebugFlagsCapability(const u32 cap); + + template <typename F> + static Result ProcessMapRegionCapability(const u32 cap, F f); + static Result CheckMapRegion(KernelCore& kernel, const u32 cap); + + Result SetCapability(const u32 cap, u32& set_flags, u32& set_svc, KPageTable* page_table); + Result SetCapabilities(std::span<const u32> caps, KPageTable* page_table); + +private: + Svc::SvcAccessFlagSet m_svc_access_flags{}; + InterruptFlagSet m_irq_access_flags{}; + u64 m_core_mask{}; + u64 m_phys_core_mask{}; + u64 m_priority_mask{}; + u32 m_debug_capabilities{}; + s32 m_handle_table_size{}; + u32 m_intended_kernel_version{}; + u32 m_program_type{}; +}; + +} // namespace Kernel |