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; | ||||
|             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: | ||||
|             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; | ||||
|             break; | ||||
|         } | ||||
|         case IPC::DescriptorType::MappedBuffer: { | ||||
|             VAddr addr = request_mapped_buffers[cmd_buf[i]].address; | ||||
|             dst_cmdbuf[i++] = addr; | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); | ||||
|         } | ||||
|  | @ -174,4 +185,28 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P | |||
|     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
 | ||||
|  |  | |||
|  | @ -63,6 +63,35 @@ protected: | |||
|     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 | ||||
|  * 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 | ||||
|  * 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. | ||||
|  * | ||||
|  * 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 { | ||||
| public: | ||||
|  | @ -131,6 +171,12 @@ public: | |||
|      */ | ||||
|     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.
 | ||||
|     ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process, | ||||
|                                                  HandleTable& src_table); | ||||
|  | @ -145,6 +191,8 @@ private: | |||
|     boost::container::small_vector<SharedPtr<Object>, 8> request_handles; | ||||
|     // The static buffers will be created when the IPC request is translated.
 | ||||
|     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
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue