mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Service: Make service registration part of the sm implementation
Also enhances the GetServiceHandle implementation to be more accurate.
This commit is contained in:
		
							parent
							
								
									e5a59ef27c
								
							
						
					
					
						commit
						23ec6b3d8f
					
				
					 6 changed files with 151 additions and 28 deletions
				
			
		|  | @ -156,6 +156,7 @@ set(SRCS | ||||||
|             hle/service/qtm/qtm_sp.cpp |             hle/service/qtm/qtm_sp.cpp | ||||||
|             hle/service/qtm/qtm_u.cpp |             hle/service/qtm/qtm_u.cpp | ||||||
|             hle/service/service.cpp |             hle/service/service.cpp | ||||||
|  |             hle/service/sm/sm.cpp | ||||||
|             hle/service/sm/srv.cpp |             hle/service/sm/srv.cpp | ||||||
|             hle/service/soc_u.cpp |             hle/service/soc_u.cpp | ||||||
|             hle/service/ssl_c.cpp |             hle/service/ssl_c.cpp | ||||||
|  | @ -352,6 +353,7 @@ set(HEADERS | ||||||
|             hle/service/qtm/qtm_sp.h |             hle/service/qtm/qtm_sp.h | ||||||
|             hle/service/qtm/qtm_u.h |             hle/service/qtm/qtm_u.h | ||||||
|             hle/service/service.h |             hle/service/service.h | ||||||
|  |             hle/service/sm/sm.h | ||||||
|             hle/service/sm/srv.h |             hle/service/sm/srv.h | ||||||
|             hle/service/soc_u.h |             hle/service/soc_u.h | ||||||
|             hle/service/ssl_c.h |             hle/service/ssl_c.h | ||||||
|  |  | ||||||
|  | @ -38,6 +38,7 @@ | ||||||
| #include "core/hle/service/ptm/ptm.h" | #include "core/hle/service/ptm/ptm.h" | ||||||
| #include "core/hle/service/qtm/qtm.h" | #include "core/hle/service/qtm/qtm.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
|  | #include "core/hle/service/sm/sm.h" | ||||||
| #include "core/hle/service/sm/srv.h" | #include "core/hle/service/sm/srv.h" | ||||||
| #include "core/hle/service/soc_u.h" | #include "core/hle/service/soc_u.h" | ||||||
| #include "core/hle/service/ssl_c.h" | #include "core/hle/service/ssl_c.h" | ||||||
|  | @ -46,7 +47,6 @@ | ||||||
| namespace Service { | namespace Service { | ||||||
| 
 | 
 | ||||||
| std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; | std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; | ||||||
| std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; |  | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Creates a function string for logging, complete with the name (or header code, depending |  * Creates a function string for logging, complete with the name (or header code, depending | ||||||
|  | @ -115,17 +115,16 @@ static void AddNamedPort(Interface* interface_) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AddService(Interface* interface_) { | void AddService(Interface* interface_) { | ||||||
|     Kernel::SharedPtr<Kernel::ServerPort> server_port; |     auto server_port = | ||||||
|     Kernel::SharedPtr<Kernel::ClientPort> client_port; |         SM::g_service_manager | ||||||
|     std::tie(server_port, client_port) = |             ->RegisterService(interface_->GetPortName(), interface_->GetMaxSessions()) | ||||||
|         Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); |             .MoveFrom(); | ||||||
| 
 |  | ||||||
|     server_port->SetHleHandler(std::shared_ptr<Interface>(interface_)); |     server_port->SetHleHandler(std::shared_ptr<Interface>(interface_)); | ||||||
|     g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Initialize ServiceManager
 | /// Initialize ServiceManager
 | ||||||
| void Init() { | void Init() { | ||||||
|  |     SM::g_service_manager = std::make_unique<SM::ServiceManager>(); | ||||||
|     AddNamedPort(new SM::SRV); |     AddNamedPort(new SM::SRV); | ||||||
|     AddNamedPort(new ERR::ERR_F); |     AddNamedPort(new ERR::ERR_F); | ||||||
| 
 | 
 | ||||||
|  | @ -187,7 +186,7 @@ void Shutdown() { | ||||||
|     AC::Shutdown(); |     AC::Shutdown(); | ||||||
|     FS::ArchiveShutdown(); |     FS::ArchiveShutdown(); | ||||||
| 
 | 
 | ||||||
|     g_srv_services.clear(); |     SM::g_service_manager = nullptr; | ||||||
|     g_kernel_named_ports.clear(); |     g_kernel_named_ports.clear(); | ||||||
|     LOG_DEBUG(Service, "shutdown OK"); |     LOG_DEBUG(Service, "shutdown OK"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -107,8 +107,6 @@ void Shutdown(); | ||||||
| 
 | 
 | ||||||
| /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
 | /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
 | ||||||
| extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; | extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; | ||||||
| /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
 |  | ||||||
| extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; |  | ||||||
| 
 | 
 | ||||||
| /// Adds a service to the services table
 | /// Adds a service to the services table
 | ||||||
| void AddService(Interface* interface_); | void AddService(Interface* interface_); | ||||||
|  |  | ||||||
							
								
								
									
										58
									
								
								src/core/hle/service/sm/sm.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/core/hle/service/sm/sm.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include <tuple> | ||||||
|  | #include "core/hle/kernel/client_session.h" | ||||||
|  | #include "core/hle/kernel/server_port.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  | #include "core/hle/service/sm/sm.h" | ||||||
|  | 
 | ||||||
|  | namespace Service { | ||||||
|  | namespace SM { | ||||||
|  | 
 | ||||||
|  | static ResultCode ValidateServiceName(const std::string& name) { | ||||||
|  |     if (name.size() <= 0 || name.size() > 8) { | ||||||
|  |         return ERR_INVALID_NAME_SIZE; | ||||||
|  |     } | ||||||
|  |     if (name.find('\0') != std::string::npos) { | ||||||
|  |         return ERR_NAME_CONTAINS_NUL; | ||||||
|  |     } | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService( | ||||||
|  |     std::string name, unsigned int max_sessions) { | ||||||
|  | 
 | ||||||
|  |     CASCADE_CODE(ValidateServiceName(name)); | ||||||
|  |     Kernel::SharedPtr<Kernel::ServerPort> server_port; | ||||||
|  |     Kernel::SharedPtr<Kernel::ClientPort> client_port; | ||||||
|  |     std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name); | ||||||
|  | 
 | ||||||
|  |     registered_services.emplace(name, std::move(client_port)); | ||||||
|  |     return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( | ||||||
|  |     const std::string& name) { | ||||||
|  | 
 | ||||||
|  |     CASCADE_CODE(ValidateServiceName(name)); | ||||||
|  |     auto it = registered_services.find(name); | ||||||
|  |     if (it == registered_services.end()) { | ||||||
|  |         return ERR_SERVICE_NOT_REGISTERED; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return MakeResult<Kernel::SharedPtr<Kernel::ClientPort>>(it->second); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToService( | ||||||
|  |     const std::string& name) { | ||||||
|  | 
 | ||||||
|  |     CASCADE_RESULT(auto client_port, GetServicePort(name)); | ||||||
|  |     return client_port->Connect(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::unique_ptr<ServiceManager> g_service_manager; | ||||||
|  | 
 | ||||||
|  | } // namespace SM
 | ||||||
|  | } // namespace Service
 | ||||||
							
								
								
									
										49
									
								
								src/core/hle/service/sm/sm.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/core/hle/service/sm/sm.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <unordered_map> | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  | #include "core/hle/service/service.h" | ||||||
|  | 
 | ||||||
|  | namespace Kernel { | ||||||
|  | class ClientPort; | ||||||
|  | class ClientSession; | ||||||
|  | class ServerPort; | ||||||
|  | class SessionRequestHandler; | ||||||
|  | } // namespace Kernel
 | ||||||
|  | 
 | ||||||
|  | namespace Service { | ||||||
|  | namespace SM { | ||||||
|  | 
 | ||||||
|  | constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(1, ErrorModule::SRV, ErrorSummary::WouldBlock, | ||||||
|  |                                                 ErrorLevel::Temporary); // 0xD0406401
 | ||||||
|  | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(2, ErrorModule::SRV, ErrorSummary::WouldBlock, | ||||||
|  |                                                  ErrorLevel::Temporary); // 0xD0406402
 | ||||||
|  | constexpr ResultCode ERR_INVALID_NAME_SIZE(5, ErrorModule::SRV, ErrorSummary::WrongArgument, | ||||||
|  |                                            ErrorLevel::Permanent); // 0xD9006405
 | ||||||
|  | constexpr ResultCode ERR_ACCESS_DENIED(6, ErrorModule::SRV, ErrorSummary::InvalidArgument, | ||||||
|  |                                        ErrorLevel::Permanent); // 0xD8E06406
 | ||||||
|  | constexpr ResultCode ERR_NAME_CONTAINS_NUL(7, ErrorModule::SRV, ErrorSummary::WrongArgument, | ||||||
|  |                                            ErrorLevel::Permanent); // 0xD9006407
 | ||||||
|  | 
 | ||||||
|  | class ServiceManager { | ||||||
|  | public: | ||||||
|  |     ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, | ||||||
|  |                                                                      unsigned int max_sessions); | ||||||
|  |     ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); | ||||||
|  |     ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
 | ||||||
|  |     std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | extern std::unique_ptr<ServiceManager> g_service_manager; | ||||||
|  | 
 | ||||||
|  | } // namespace SM
 | ||||||
|  | } // namespace Service
 | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include "core/hle/kernel/client_session.h" | #include "core/hle/kernel/client_session.h" | ||||||
| #include "core/hle/kernel/semaphore.h" | #include "core/hle/kernel/semaphore.h" | ||||||
| #include "core/hle/kernel/server_session.h" | #include "core/hle/kernel/server_session.h" | ||||||
|  | #include "core/hle/service/sm/sm.h" | ||||||
| #include "core/hle/service/sm/srv.h" | #include "core/hle/service/sm/srv.h" | ||||||
| 
 | 
 | ||||||
| namespace Service { | namespace Service { | ||||||
|  | @ -78,25 +79,41 @@ static void GetServiceHandle(Interface* self) { | ||||||
|     ResultCode res = RESULT_SUCCESS; |     ResultCode res = RESULT_SUCCESS; | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); |     size_t name_len = cmd_buff[3]; | ||||||
|     auto it = Service::g_srv_services.find(port_name); |     if (name_len > Service::kMaxPortSize) { | ||||||
| 
 |         cmd_buff[1] = ERR_INVALID_NAME_SIZE.raw; | ||||||
|     if (it != Service::g_srv_services.end()) { |         LOG_ERROR(Service_SRV, "called name_len=0x%X, failed with code=0x%08X", name_len, | ||||||
|         auto client_port = it->second; |                   cmd_buff[1]); | ||||||
| 
 |         return; | ||||||
|         auto client_session = client_port->Connect(); |     } | ||||||
|         res = client_session.Code(); |     std::string name(reinterpret_cast<const char*>(&cmd_buff[1]), name_len); | ||||||
| 
 |     bool return_port_on_failure = (cmd_buff[4] & 1) == 0; | ||||||
|         if (client_session.Succeeded()) { | 
 | ||||||
|             // Return the client session
 |     // TODO(yuriks): Permission checks go here
 | ||||||
|             cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); | 
 | ||||||
|         } |     auto client_port = g_service_manager->GetServicePort(name); | ||||||
|         LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); |     if (client_port.Failed()) { | ||||||
|     } else { |         cmd_buff[1] = client_port.Code().raw; | ||||||
|         LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); |         LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(), | ||||||
|         res = UnimplementedFunction(ErrorModule::SRV); |                   cmd_buff[1]); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto session = client_port.Unwrap()->Connect(); | ||||||
|  |     cmd_buff[1] = session.Code().raw; | ||||||
|  |     if (session.Succeeded()) { | ||||||
|  |         cmd_buff[3] = Kernel::g_handle_table.Create(session.MoveFrom()).MoveFrom(); | ||||||
|  |         LOG_DEBUG(Service_SRV, "called service=%s, session handle=0x%08X", name.c_str(), | ||||||
|  |                   cmd_buff[3]); | ||||||
|  |     } else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED && return_port_on_failure) { | ||||||
|  |         cmd_buff[1] = ERR_MAX_CONNECTIONS_REACHED.raw; | ||||||
|  |         cmd_buff[3] = Kernel::g_handle_table.Create(client_port.MoveFrom()).MoveFrom(); | ||||||
|  |         LOG_WARNING(Service_SRV, "called service=%s, *port* handle=0x%08X", name.c_str(), | ||||||
|  |                     cmd_buff[3]); | ||||||
|  |     } else { | ||||||
|  |         LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(), | ||||||
|  |                   cmd_buff[1]); | ||||||
|     } |     } | ||||||
|     cmd_buff[1] = res.raw; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue