diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/service/acc/acc.cpp | 34 | ||||
-rw-r--r-- | src/core/hle/service/acc/acc.h | 1 | ||||
-rw-r--r-- | src/core/hle/service/acc/acc_u0.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/acc/profile_manager.cpp | 25 | ||||
-rw-r--r-- | src/core/hle/service/acc/profile_manager.h | 3 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/devices/nvmap.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/service/service.cpp | 21 | ||||
-rw-r--r-- | src/core/hle/service/service.h | 4 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.cpp | 43 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.h | 2 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm_controller.cpp | 41 |
11 files changed, 117 insertions, 65 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index bb838e285..85a3f0802 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -512,10 +512,11 @@ protected: class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { public: - explicit IManagerForApplication(Core::System& system_, Common::UUID user_id_) + explicit IManagerForApplication(Core::System& system_, + const std::shared_ptr<ProfileManager>& profile_manager_) : ServiceFramework{system_, "IManagerForApplication"}, ensure_token_id{std::make_shared<EnsureTokenIdCacheAsyncInterface>(system)}, - user_id{user_id_} { + profile_manager{profile_manager_} { // clang-format off static const FunctionInfo functions[] = { {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"}, @@ -545,7 +546,7 @@ private: IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushRaw<u64>(user_id.Hash()); + rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash()); } void EnsureIdTokenCacheAsync(Kernel::HLERequestContext& ctx) { @@ -575,17 +576,20 @@ private: IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushRaw<u64>(user_id.Hash()); + rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash()); } void StoreOpenContext(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); + LOG_DEBUG(Service_ACC, "called"); + + profile_manager->StoreOpenedUsers(); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } std::shared_ptr<EnsureTokenIdCacheAsyncInterface> ensure_token_id{}; - Common::UUID user_id{}; + std::shared_ptr<ProfileManager> profile_manager; }; // 6.0.0+ @@ -790,7 +794,7 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo LOG_DEBUG(Service_ACC, "called"); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser()); + rb.PushIpcInterface<IManagerForApplication>(system, profile_manager); } void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx) { @@ -849,22 +853,10 @@ void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } -void Module::Interface::LoadOpenContext(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - - // This is similar to GetBaasAccountManagerForApplication - // This command is used concurrently with ListOpenContextStoredUsers - // TODO: Find the differences between this and GetBaasAccountManagerForApplication - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser()); -} - void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); + LOG_DEBUG(Service_ACC, "called"); - // TODO(ogniK): Handle open contexts - ctx.WriteBuffer(profile_manager->GetOpenUsers()); + ctx.WriteBuffer(profile_manager->GetStoredOpenedUsers()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index 1621e7c0a..9411b0b92 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -35,7 +35,6 @@ public: void InitializeApplicationInfoV2(Kernel::HLERequestContext& ctx); void GetProfileEditor(Kernel::HLERequestContext& ctx); void ListQualifiedUsers(Kernel::HLERequestContext& ctx); - void LoadOpenContext(Kernel::HLERequestContext& ctx); void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx); void StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx); void StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 65023b8c2..54844bfe7 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -28,7 +28,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> {110, &ACC_U0::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"}, {111, nullptr, "ClearSaveDataThumbnail"}, {120, nullptr, "CreateGuestLoginRequest"}, - {130, &ACC_U0::LoadOpenContext, "LoadOpenContext"}, // 5.0.0+ + {130, nullptr, "LoadOpenContext"}, // 5.0.0+ {131, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 6.0.0+ {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+ {141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index a58da4d5f..481e0d141 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -261,6 +261,31 @@ UUID ProfileManager::GetLastOpenedUser() const { return last_opened_user; } +/// Gets the list of stored opened users. +UserIDArray ProfileManager::GetStoredOpenedUsers() const { + UserIDArray output{}; + std::ranges::transform(stored_opened_profiles, output.begin(), [](const ProfileInfo& p) { + if (p.is_open) + return p.user_uuid; + return Common::InvalidUUID; + }); + std::stable_partition(output.begin(), output.end(), + [](const UUID& uuid) { return uuid.IsValid(); }); + return output; +} + +/// Captures the opened users, which can be queried across process launches with +/// ListOpenContextStoredUsers. +void ProfileManager::StoreOpenedUsers() { + size_t profile_index{}; + stored_opened_profiles = {}; + std::for_each(profiles.begin(), profiles.end(), [&](const auto& profile) { + if (profile.is_open) { + stored_opened_profiles[profile_index++] = profile; + } + }); +} + /// Return the users profile base and the unknown arbitary data. bool ProfileManager::GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile, UserData& data) const { diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 135f7d0d5..993a5a57a 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h @@ -86,6 +86,8 @@ public: UserIDArray GetOpenUsers() const; UserIDArray GetAllUsers() const; Common::UUID GetLastOpenedUser() const; + UserIDArray GetStoredOpenedUsers() const; + void StoreOpenedUsers(); bool CanSystemRegisterUser() const; @@ -101,6 +103,7 @@ private: bool RemoveProfileAtIndex(std::size_t index); std::array<ProfileInfo, MAX_USERS> profiles{}; + std::array<ProfileInfo, MAX_USERS> stored_opened_profiles{}; std::size_t user_count{}; Common::UUID last_opened_user{}; }; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 44388655d..fa29db758 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -126,10 +126,12 @@ NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); return result; } + bool is_out_io{}; ASSERT(system.CurrentProcess() ->PageTable() - .LockForMapDeviceAddressSpace(handle_description->address, handle_description->size, - Kernel::KMemoryPermission::None, true) + .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address, + handle_description->size, + Kernel::KMemoryPermission::None, true, false) .IsSuccess()); std::memcpy(output.data(), ¶ms, sizeof(params)); return result; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5db6588e4..5ab41c0c4 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -99,6 +99,12 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se ServiceFrameworkBase::~ServiceFrameworkBase() { // Wait for other threads to release access before destroying const auto guard = LockService(); + + if (named_port != nullptr) { + named_port->GetClientPort().Close(); + named_port->GetServerPort().Close(); + named_port = nullptr; + } } void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { @@ -113,15 +119,16 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) Kernel::KClientPort& ServiceFrameworkBase::CreatePort() { const auto guard = LockService(); - ASSERT(!service_registered); + if (named_port == nullptr) { + ASSERT(!service_registered); - auto* port = Kernel::KPort::Create(kernel); - port->Initialize(max_sessions, false, service_name); - port->GetServerPort().SetSessionHandler(shared_from_this()); + named_port = Kernel::KPort::Create(kernel); + named_port->Initialize(max_sessions, false, service_name); - service_registered = true; + service_registered = true; + } - return port->GetClientPort(); + return named_port->GetClientPort(); } void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { @@ -199,7 +206,6 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, switch (ctx.GetCommandType()) { case IPC::CommandType::Close: case IPC::CommandType::TIPC_Close: { - session.Close(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); result = IPC::ERR_REMOTE_PROCESS_DEAD; @@ -244,6 +250,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory); + system.Kernel().RegisterInterfaceForNamedService("sm:", SM::ServiceManager::SessionHandler); Account::InstallInterfaces(system); AM::InstallInterfaces(*sm, *nv_flinger, system); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index ec9deeee4..22e2119d7 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -20,6 +20,7 @@ class System; namespace Kernel { class HLERequestContext; class KClientPort; +class KPort; class KServerSession; class ServiceThread; } // namespace Kernel @@ -98,6 +99,9 @@ protected: /// Identifier string used to connect to the service. std::string service_name; + /// Port used by ManageNamedPort. + Kernel::KPort* named_port{}; + private: template <typename T> friend class ServiceFramework; diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index e2b8d8720..84720094f 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -23,7 +23,13 @@ constexpr Result ERR_INVALID_NAME(ErrorModule::SM, 6); constexpr Result ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {} -ServiceManager::~ServiceManager() = default; + +ServiceManager::~ServiceManager() { + for (auto& [name, port] : service_ports) { + port->GetClientPort().Close(); + port->GetServerPort().Close(); + } +} void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { controller_interface->InvokeRequest(context); @@ -43,6 +49,10 @@ Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core return self.sm_interface->CreatePort(); } +void ServiceManager::SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port) { + self.sm_interface->AcceptSession(server_port); +} + Result ServiceManager::RegisterService(std::string name, u32 max_sessions, Kernel::SessionRequestHandlerPtr handler) { @@ -53,7 +63,11 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions, return ERR_ALREADY_REGISTERED; } - registered_services.emplace(std::move(name), handler); + auto* port = Kernel::KPort::Create(kernel); + port->Initialize(ServerSessionCountMax, false, name); + + service_ports.emplace(name, port); + registered_services.emplace(name, handler); return ResultSuccess; } @@ -68,24 +82,20 @@ Result ServiceManager::UnregisterService(const std::string& name) { } registered_services.erase(iter); + service_ports.erase(name); + return ResultSuccess; } ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) { CASCADE_CODE(ValidateServiceName(name)); - auto it = registered_services.find(name); - if (it == registered_services.end()) { + auto it = service_ports.find(name); + if (it == service_ports.end()) { LOG_ERROR(Service_SM, "Server is not registered! service={}", name); return ERR_SERVICE_NOT_REGISTERED; } - auto* port = Kernel::KPort::Create(kernel); - - port->Initialize(ServerSessionCountMax, false, name); - auto handler = it->second; - port->GetServerPort().SetSessionHandler(std::move(handler)); - - return port; + return it->second; } /** @@ -144,23 +154,20 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& // Find the named port. auto port_result = service_manager.GetServicePort(name); - if (port_result.Failed()) { + auto service = service_manager.GetService<Kernel::SessionRequestHandler>(name); + if (port_result.Failed() || !service) { LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw); return port_result.Code(); } auto& port = port_result.Unwrap(); - SCOPE_EXIT({ port->GetClientPort().Close(); }); - - kernel.RegisterServerObject(&port->GetServerPort()); // Create a new session. Kernel::KClientSession* session{}; - if (const auto result = port->GetClientPort().CreateSession( - std::addressof(session), std::make_shared<Kernel::SessionRequestManager>(kernel)); - result.IsError()) { + if (const auto result = port->GetClientPort().CreateSession(&session); result.IsError()) { LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); return result; } + service->AcceptSession(&port->GetServerPort()); LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 878decc6f..02a5dde9e 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -51,6 +51,7 @@ private: class ServiceManager { public: static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system); + static void SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port); explicit ServiceManager(Kernel::KernelCore& kernel_); ~ServiceManager(); @@ -78,6 +79,7 @@ private: /// Map of registered services, retrieved using GetServicePort. std::unordered_map<std::string, Kernel::SessionRequestHandlerPtr> registered_services; + std::unordered_map<std::string, Kernel::KPort*> service_ports; /// Kernel context Kernel::KernelCore& kernel; diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp index 273f79568..69e0fe808 100644 --- a/src/core/hle/service/sm/sm_controller.cpp +++ b/src/core/hle/service/sm/sm_controller.cpp @@ -15,10 +15,9 @@ namespace Service::SM { void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { - ASSERT_MSG(!ctx.Session()->GetSessionRequestManager()->IsDomain(), - "Session is already a domain"); + ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Session is already a domain"); LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); - ctx.Session()->GetSessionRequestManager()->ConvertToDomainOnRequestEnd(); + ctx.GetManager()->ConvertToDomainOnRequestEnd(); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -28,23 +27,35 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service, "called"); - auto& parent_session = *ctx.Session()->GetParent(); - auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort(); - auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager(); + auto& process = *ctx.GetThread().GetOwnerProcess(); + auto session_manager = ctx.GetManager(); - // Create a session. - Kernel::KClientSession* session{}; - const Result result = parent_port.CreateSession(std::addressof(session), session_manager); - if (result.IsError()) { - LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - } + // FIXME: this is duplicated from the SVC, it should just call it instead + // once this is a proper process + + // Reserve a new session from the process resource limit. + Kernel::KScopedResourceReservation session_reservation(&process, + Kernel::LimitableResource::Sessions); + ASSERT(session_reservation.Succeeded()); + + // Create the session. + Kernel::KSession* session = Kernel::KSession::Create(system.Kernel()); + ASSERT(session != nullptr); + + // Initialize the session. + session->Initialize(nullptr, ""); + + // Commit the session reservation. + session_reservation.Commit(); + + // Register with manager. + session_manager->SessionHandler().RegisterSession(&session->GetServerSession(), + session_manager); // We succeeded. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(ResultSuccess); - rb.PushMoveObjects(session); + rb.PushMoveObjects(session->GetClientSession()); } void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { |