diff options
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/kernel/init/init_slab_setup.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_device_address_space.cpp | 150 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_device_address_space.h | 60 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc_types.h | 14 | 
5 files changed, 230 insertions, 0 deletions
| diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 7b363eb1e..571acf4b2 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -11,6 +11,7 @@  #include "core/hle/kernel/init/init_slab_setup.h"  #include "core/hle/kernel/k_code_memory.h"  #include "core/hle/kernel/k_debug.h" +#include "core/hle/kernel/k_device_address_space.h"  #include "core/hle/kernel/k_event.h"  #include "core/hle/kernel/k_event_info.h"  #include "core/hle/kernel/k_memory_layout.h" @@ -43,6 +44,7 @@ namespace Kernel::Init {      HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__)                     \      HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__)                         \      HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__)                                 \ +    HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ##__VA_ARGS__)                 \      HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__)                                       \      HANDLER(KThreadLocalPage,                                                                      \              (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8),             \ diff --git a/src/core/hle/kernel/k_device_address_space.cpp b/src/core/hle/kernel/k_device_address_space.cpp new file mode 100644 index 000000000..27659ea3b --- /dev/null +++ b/src/core/hle/kernel/k_device_address_space.cpp @@ -0,0 +1,150 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "core/core.h" +#include "core/hle/kernel/k_device_address_space.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +KDeviceAddressSpace::KDeviceAddressSpace(KernelCore& kernel_) +    : KAutoObjectWithSlabHeapAndContainer(kernel_), m_lock(kernel_), m_is_initialized(false) {} +KDeviceAddressSpace::~KDeviceAddressSpace() = default; + +void KDeviceAddressSpace::Initialize() { +    // This just forwards to the device page table manager. +    // KDevicePageTable::Initialize(); +} + +// Member functions. +Result KDeviceAddressSpace::Initialize(u64 address, u64 size) { +    // Initialize the device page table. +    // R_TRY(m_table.Initialize(address, size)); + +    // Set member variables. +    m_space_address = address; +    m_space_size = size; +    m_is_initialized = true; + +    R_SUCCEED(); +} + +void KDeviceAddressSpace::Finalize() { +    // Finalize the table. +    // m_table.Finalize(); +} + +Result KDeviceAddressSpace::Attach(Svc::DeviceName device_name) { +    // Lock the address space. +    KScopedLightLock lk(m_lock); + +    // Attach. +    // R_RETURN(m_table.Attach(device_name, m_space_address, m_space_size)); +    R_SUCCEED(); +} + +Result KDeviceAddressSpace::Detach(Svc::DeviceName device_name) { +    // Lock the address space. +    KScopedLightLock lk(m_lock); + +    // Detach. +    // R_RETURN(m_table.Detach(device_name)); +    R_SUCCEED(); +} + +Result KDeviceAddressSpace::Map(KPageTable* page_table, VAddr process_address, size_t size, +                                u64 device_address, u32 option, bool is_aligned) { +    // Check that the address falls within the space. +    R_UNLESS((m_space_address <= device_address && +              device_address + size - 1 <= m_space_address + m_space_size - 1), +             ResultInvalidCurrentMemory); + +    // Decode the option. +    const Svc::MapDeviceAddressSpaceOption option_pack{option}; +    const auto device_perm = option_pack.permission.Value(); +    const auto flags = option_pack.flags.Value(); +    const auto reserved = option_pack.reserved.Value(); + +    // Validate the option. +    // TODO: It is likely that this check for flags == none is only on NX board. +    R_UNLESS(flags == Svc::MapDeviceAddressSpaceFlag::None, ResultInvalidEnumValue); +    R_UNLESS(reserved == 0, ResultInvalidEnumValue); + +    // Lock the address space. +    KScopedLightLock lk(m_lock); + +    // Lock the page table to prevent concurrent device mapping operations. +    // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); + +    // Lock the pages. +    bool is_io{}; +    R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size, +                                                   ConvertToKMemoryPermission(device_perm), +                                                   is_aligned, true)); + +    // Ensure that if we fail, we don't keep unmapped pages locked. +    ON_RESULT_FAILURE { +        ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess); +    }; + +    // Check that the io status is allowable. +    if (is_io) { +        R_UNLESS(static_cast<u32>(flags & Svc::MapDeviceAddressSpaceFlag::NotIoRegister) == 0, +                 ResultInvalidCombination); +    } + +    // Map the pages. +    { +        // Perform the mapping. +        // R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm, +        //                   is_aligned, is_io)); + +        // Ensure that we unmap the pages if we fail to update the protections. +        // NOTE: Nintendo does not check the result of this unmap call. +        // ON_RESULT_FAILURE { m_table.Unmap(device_address, size); }; + +        // Update the protections in accordance with how much we mapped. +        // R_TRY(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size)); +    } + +    // We succeeded. +    R_SUCCEED(); +} + +Result KDeviceAddressSpace::Unmap(KPageTable* page_table, VAddr process_address, size_t size, +                                  u64 device_address) { +    // Check that the address falls within the space. +    R_UNLESS((m_space_address <= device_address && +              device_address + size - 1 <= m_space_address + m_space_size - 1), +             ResultInvalidCurrentMemory); + +    // Lock the address space. +    KScopedLightLock lk(m_lock); + +    // Lock the page table to prevent concurrent device mapping operations. +    // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); + +    // Lock the pages. +    R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true)); + +    // Unmap the pages. +    { +        // If we fail to unmap, we want to do a partial unlock. +        // ON_RESULT_FAILURE { +        //     ASSERT(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size) == +        //            ResultSuccess); +        // }; + +        // Perform the unmap. +        // R_TRY(m_table.Unmap(page_table, process_address, size, device_address)); +    } + +    // Unlock the pages. +    ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess); + +    R_SUCCEED(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_device_address_space.h b/src/core/hle/kernel/k_device_address_space.h new file mode 100644 index 000000000..4709df995 --- /dev/null +++ b/src/core/hle/kernel/k_device_address_space.h @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <string> + +#include "common/common_types.h" +#include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KDeviceAddressSpace final +    : public KAutoObjectWithSlabHeapAndContainer<KDeviceAddressSpace, KAutoObjectWithList> { +    KERNEL_AUTOOBJECT_TRAITS(KDeviceAddressSpace, KAutoObject); + +public: +    explicit KDeviceAddressSpace(KernelCore& kernel); +    ~KDeviceAddressSpace(); + +    Result Initialize(u64 address, u64 size); +    void Finalize(); + +    bool IsInitialized() const { +        return m_is_initialized; +    } +    static void PostDestroy(uintptr_t arg) {} + +    Result Attach(Svc::DeviceName device_name); +    Result Detach(Svc::DeviceName device_name); + +    Result MapByForce(KPageTable* page_table, VAddr process_address, size_t size, +                      u64 device_address, u32 option) { +        R_RETURN(this->Map(page_table, process_address, size, device_address, option, false)); +    } + +    Result MapAligned(KPageTable* page_table, VAddr process_address, size_t size, +                      u64 device_address, u32 option) { +        R_RETURN(this->Map(page_table, process_address, size, device_address, option, true)); +    } + +    Result Unmap(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address); + +    static void Initialize(); + +private: +    Result Map(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address, +               u32 option, bool is_aligned); + +private: +    KLightLock m_lock; +    // KDevicePageTable m_table; +    u64 m_space_address{}; +    u64 m_space_size{}; +    bool m_is_initialized{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 8d22f8d2c..5f52e1e95 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -35,6 +35,7 @@ class GlobalSchedulerContext;  class KAutoObjectWithListContainer;  class KClientSession;  class KDebug; +class KDeviceAddressSpace;  class KDynamicPageManager;  class KEvent;  class KEventInfo; @@ -359,6 +360,8 @@ public:              return slab_heap_container->transfer_memory;          } else if constexpr (std::is_same_v<T, KCodeMemory>) {              return slab_heap_container->code_memory; +        } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) { +            return slab_heap_container->device_address_space;          } else if constexpr (std::is_same_v<T, KPageBuffer>) {              return slab_heap_container->page_buffer;          } else if constexpr (std::is_same_v<T, KThreadLocalPage>) { @@ -431,6 +434,7 @@ private:          KSlabHeap<KThread> thread;          KSlabHeap<KTransferMemory> transfer_memory;          KSlabHeap<KCodeMemory> code_memory; +        KSlabHeap<KDeviceAddressSpace> device_address_space;          KSlabHeap<KPageBuffer> page_buffer;          KSlabHeap<KThreadLocalPage> thread_local_page;          KSlabHeap<KSessionRequest> session_request; diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index 9c2f9998a..e90c35601 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h @@ -5,6 +5,7 @@  #include <bitset> +#include "common/bit_field.h"  #include "common/common_funcs.h"  #include "common/common_types.h" @@ -498,6 +499,19 @@ enum class MemoryMapping : u32 {      Memory = 2,  }; +enum class MapDeviceAddressSpaceFlag : u32 { +    None = (0U << 0), +    NotIoRegister = (1U << 0), +}; +DECLARE_ENUM_FLAG_OPERATORS(MapDeviceAddressSpaceFlag); + +union MapDeviceAddressSpaceOption { +    u32 raw; +    BitField<0, 16, MemoryPermission> permission; +    BitField<16, 1, MapDeviceAddressSpaceFlag> flags; +    BitField<17, 15, u32> reserved; +}; +  enum class KernelDebugType : u32 {      Thread = 0,      ThreadCallStack = 1, | 
