mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Kernel/IPC: Implement MappedBuffer translation for HLE services that use the HLERequestContext architecture.
This commit is contained in:
		
							parent
							
								
									4071da5012
								
							
						
					
					
						commit
						3ecf650bf9
					
				
					 2 changed files with 83 additions and 0 deletions
				
			
		|  | @ -107,6 +107,12 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr | ||||||
|             cmd_buf[i++] = source_address; |             cmd_buf[i++] = source_address; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |         case IPC::DescriptorType::MappedBuffer: { | ||||||
|  |             u32 next_id = static_cast<u32>(request_mapped_buffers.size()); | ||||||
|  |             request_mapped_buffers.emplace_back(src_process, descriptor, src_cmdbuf[i], next_id); | ||||||
|  |             cmd_buf[i++] = next_id; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|         default: |         default: | ||||||
|             UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); |             UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); | ||||||
|         } |         } | ||||||
|  | @ -166,6 +172,11 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P | ||||||
|             dst_cmdbuf[i++] = target_address; |             dst_cmdbuf[i++] = target_address; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |         case IPC::DescriptorType::MappedBuffer: { | ||||||
|  |             VAddr addr = request_mapped_buffers[cmd_buf[i]].address; | ||||||
|  |             dst_cmdbuf[i++] = addr; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|         default: |         default: | ||||||
|             UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); |             UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); | ||||||
|         } |         } | ||||||
|  | @ -174,4 +185,28 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | MappedBuffer& HLERequestContext::GetMappedBuffer(u32 id_from_cmdbuf) { | ||||||
|  |     ASSERT_MSG(id_from_cmdbuf < request_mapped_buffers.size(), "Mapped Buffer ID out of range!"); | ||||||
|  |     return request_mapped_buffers[id_from_cmdbuf]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MappedBuffer::MappedBuffer(const Process& process, u32 descriptor, VAddr address, u32 id) | ||||||
|  |     : process(&process), address(address), id(id) { | ||||||
|  |     IPC::MappedBufferDescInfo desc{descriptor}; | ||||||
|  |     size = desc.size; | ||||||
|  |     perms = desc.perms; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MappedBuffer::Read(void* dest_buffer, size_t offset, size_t size) { | ||||||
|  |     ASSERT(perms & IPC::R); | ||||||
|  |     ASSERT(offset + size <= this->size); | ||||||
|  |     Memory::ReadBlock(*process, address + offset, dest_buffer, size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MappedBuffer::Write(const void* src_buffer, size_t offset, size_t size) { | ||||||
|  |     ASSERT(perms & IPC::W); | ||||||
|  |     ASSERT(offset + size <= this->size); | ||||||
|  |     Memory::WriteBlock(*process, address + offset, src_buffer, size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace Kernel
 | } // namespace Kernel
 | ||||||
|  |  | ||||||
|  | @ -63,6 +63,35 @@ protected: | ||||||
|     std::vector<SharedPtr<ServerSession>> connected_sessions; |     std::vector<SharedPtr<ServerSession>> connected_sessions; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | class MappedBuffer { | ||||||
|  | public: | ||||||
|  |     MappedBuffer(const Process& process, u32 descriptor, VAddr address, u32 id); | ||||||
|  | 
 | ||||||
|  |     // interface for service
 | ||||||
|  |     void Read(void* dest_buffer, size_t offset, size_t size); | ||||||
|  |     void Write(const void* src_buffer, size_t offset, size_t size); | ||||||
|  |     size_t GetSize() const { | ||||||
|  |         return size; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // interface for ipc helper
 | ||||||
|  |     u32 GenerateDescriptor() const { | ||||||
|  |         return IPC::MappedBufferDesc(size, perms); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u32 GetId() const { | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     friend class HLERequestContext; | ||||||
|  |     u32 id; | ||||||
|  |     VAddr address; | ||||||
|  |     const Process* process; | ||||||
|  |     size_t size; | ||||||
|  |     IPC::MappedBufferPermissions perms; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Class containing information about an in-flight IPC request being handled by an HLE service |  * Class containing information about an in-flight IPC request being handled by an HLE service | ||||||
|  * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and |  * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and | ||||||
|  | @ -81,6 +110,17 @@ protected: | ||||||
|  * The end result is similar to just giving services their own real handle tables, but since these |  * The end result is similar to just giving services their own real handle tables, but since these | ||||||
|  * ids are local to a specific context, it avoids requiring services to manage handles for objects |  * ids are local to a specific context, it avoids requiring services to manage handles for objects | ||||||
|  * across multiple calls and ensuring that unneeded handles are cleaned up. |  * across multiple calls and ensuring that unneeded handles are cleaned up. | ||||||
|  |  * | ||||||
|  |  * HLE mapped buffer protocol | ||||||
|  |  * ========================== | ||||||
|  |  * | ||||||
|  |  * HLE services don't have their own virtual memory space, a tweaked protocol is used to simulate | ||||||
|  |  * memory mapping. The kernel will wrap the incoming buffers into a memory interface on which HLE | ||||||
|  |  * services can operate, and insert a id in the buffer where the vaddr would normally be. The | ||||||
|  |  * service then calls GetMappedBuffer with that id to get the memory interface. On response, like | ||||||
|  |  * real services pushing back the mapped buffer address to unmap it, HLE services push back the | ||||||
|  |  * id of the memory interface and let kernel convert it back to client vaddr. No real unmapping is | ||||||
|  |  * needed in this case, though. | ||||||
|  */ |  */ | ||||||
| class HLERequestContext { | class HLERequestContext { | ||||||
| public: | public: | ||||||
|  | @ -131,6 +171,12 @@ public: | ||||||
|      */ |      */ | ||||||
|     void AddStaticBuffer(u8 buffer_id, std::vector<u8> data); |     void AddStaticBuffer(u8 buffer_id, std::vector<u8> data); | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets a memory interface by the id from the request command buffer. See the "HLE mapped buffer | ||||||
|  |      * protocol" section in the class documentation for more details. | ||||||
|  |      */ | ||||||
|  |     MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf); | ||||||
|  | 
 | ||||||
|     /// Populates this context with data from the requesting process/thread.
 |     /// Populates this context with data from the requesting process/thread.
 | ||||||
|     ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process, |     ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process, | ||||||
|                                                  HandleTable& src_table); |                                                  HandleTable& src_table); | ||||||
|  | @ -145,6 +191,8 @@ private: | ||||||
|     boost::container::small_vector<SharedPtr<Object>, 8> request_handles; |     boost::container::small_vector<SharedPtr<Object>, 8> request_handles; | ||||||
|     // The static buffers will be created when the IPC request is translated.
 |     // The static buffers will be created when the IPC request is translated.
 | ||||||
|     std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers; |     std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers; | ||||||
|  |     // The mapped buffers will be created when the IPC request is translated
 | ||||||
|  |     boost::container::small_vector<MappedBuffer, 8> request_mapped_buffers; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Kernel
 | } // namespace Kernel
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue