diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -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 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/lobby.cpp | 16 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/lobby.h | 2 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/lobby.ui | 7 | 
10 files changed, 258 insertions, 1 deletions
| diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3eee1cfbe..112c61b80 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -195,6 +195,8 @@ add_library(core STATIC      hle/kernel/k_condition_variable.cpp      hle/kernel/k_condition_variable.h      hle/kernel/k_debug.h +    hle/kernel/k_device_address_space.cpp +    hle/kernel/k_device_address_space.h      hle/kernel/k_dynamic_page_manager.h      hle/kernel/k_dynamic_resource_manager.h      hle/kernel/k_dynamic_slab_heap.h 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, diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index cab44bf9c..447d624e1 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -1083,7 +1083,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {  }  void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) { -    const auto raw = ctx.ReadBuffer(); +    const auto raw = ctx.ReadBufferCopy();      auto log = Common::StringFromFixedZeroTerminatedBuffer(          reinterpret_cast<const char*>(raw.data()), raw.size()); diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index 08c275696..6c93e3511 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -77,6 +77,7 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,      // UI Buttons      connect(ui->refresh_list, &QPushButton::clicked, this, &Lobby::RefreshLobby);      connect(ui->games_owned, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterOwned); +    connect(ui->hide_empty, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterEmpty);      connect(ui->hide_full, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterFull);      connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch);      connect(ui->room_list, &QTreeView::doubleClicked, this, &Lobby::OnJoinRoom); @@ -329,6 +330,16 @@ bool LobbyFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s          return true;      } +    // filter by empty rooms +    if (filter_empty) { +        QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent); +        int player_count = +            sourceModel()->data(member_list, LobbyItemMemberList::MemberListRole).toList().size(); +        if (player_count == 0) { +            return false; +        } +    } +      // filter by filled rooms      if (filter_full) {          QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent); @@ -399,6 +410,11 @@ void LobbyFilterProxyModel::SetFilterOwned(bool filter) {      invalidate();  } +void LobbyFilterProxyModel::SetFilterEmpty(bool filter) { +    filter_empty = filter; +    invalidate(); +} +  void LobbyFilterProxyModel::SetFilterFull(bool filter) {      filter_full = filter;      invalidate(); diff --git a/src/yuzu/multiplayer/lobby.h b/src/yuzu/multiplayer/lobby.h index 300dad13e..2674ae7c3 100644 --- a/src/yuzu/multiplayer/lobby.h +++ b/src/yuzu/multiplayer/lobby.h @@ -130,12 +130,14 @@ public:  public slots:      void SetFilterOwned(bool); +    void SetFilterEmpty(bool);      void SetFilterFull(bool);      void SetFilterSearch(const QString&);  private:      QStandardItemModel* game_list;      bool filter_owned = false; +    bool filter_empty = false;      bool filter_full = false;      QString filter_search;  }; diff --git a/src/yuzu/multiplayer/lobby.ui b/src/yuzu/multiplayer/lobby.ui index 4c9901c9a..0ef0ef762 100644 --- a/src/yuzu/multiplayer/lobby.ui +++ b/src/yuzu/multiplayer/lobby.ui @@ -78,6 +78,13 @@            </widget>           </item>           <item> +          <widget class="QCheckBox" name="hide_empty"> +           <property name="text"> +            <string>Hide Empty Rooms</string> +           </property> +          </widget> +         </item> +         <item>            <widget class="QCheckBox" name="hide_full">             <property name="text">              <string>Hide Full Rooms</string> | 
