mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Kernel/IPC: Added a function to translate the IPC command buffer from one process to another.
Currently only CopyHandle, MoveHandle and CallingPid descriptors are implemented.
This commit is contained in:
		
							parent
							
								
									b579bf0cc2
								
							
						
					
					
						commit
						7cf7999e02
					
				
					 4 changed files with 110 additions and 1 deletions
				
			
		|  | @ -61,6 +61,7 @@ set(SRCS | ||||||
|             hle/kernel/timer.cpp |             hle/kernel/timer.cpp | ||||||
|             hle/kernel/vm_manager.cpp |             hle/kernel/vm_manager.cpp | ||||||
|             hle/kernel/wait_object.cpp |             hle/kernel/wait_object.cpp | ||||||
|  |             hle/kernel/ipc.cpp | ||||||
|             hle/lock.cpp |             hle/lock.cpp | ||||||
|             hle/romfs.cpp |             hle/romfs.cpp | ||||||
|             hle/service/ac/ac.cpp |             hle/service/ac/ac.cpp | ||||||
|  | @ -247,6 +248,7 @@ set(HEADERS | ||||||
|             hle/kernel/event.h |             hle/kernel/event.h | ||||||
|             hle/kernel/handle_table.h |             hle/kernel/handle_table.h | ||||||
|             hle/kernel/hle_ipc.h |             hle/kernel/hle_ipc.h | ||||||
|  |             hle/kernel/ipc.h | ||||||
|             hle/kernel/kernel.h |             hle/kernel/kernel.h | ||||||
|             hle/kernel/memory.h |             hle/kernel/memory.h | ||||||
|             hle/kernel/mutex.h |             hle/kernel/mutex.h | ||||||
|  |  | ||||||
|  | @ -7,7 +7,6 @@ | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 |  | ||||||
| namespace ErrCodes { | namespace ErrCodes { | ||||||
| enum { | enum { | ||||||
|     OutOfHandles = 19, |     OutOfHandles = 19, | ||||||
|  | @ -18,6 +17,7 @@ enum { | ||||||
|     WrongPermission = 46, |     WrongPermission = 46, | ||||||
|     InvalidBufferDescriptor = 48, |     InvalidBufferDescriptor = 48, | ||||||
|     MaxConnectionsReached = 52, |     MaxConnectionsReached = 52, | ||||||
|  |     CommandTooLarge = 54, | ||||||
| }; | }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										93
									
								
								src/core/hle/kernel/ipc.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/core/hle/kernel/ipc.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,93 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "core/hle/ipc.h" | ||||||
|  | #include "core/hle/kernel/handle_table.h" | ||||||
|  | #include "core/hle/kernel/ipc.h" | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/kernel/memory.h" | ||||||
|  | #include "core/hle/kernel/process.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
|  | #include "core/memory.h" | ||||||
|  | 
 | ||||||
|  | namespace Kernel { | ||||||
|  | 
 | ||||||
|  | ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread> dst_thread, | ||||||
|  |                                   VAddr src_address, VAddr dst_address) { | ||||||
|  | 
 | ||||||
|  |     auto& src_process = src_thread->owner_process; | ||||||
|  | 
 | ||||||
|  |     IPC::Header header; | ||||||
|  |     // TODO(Subv): Replace by Memory::Read32 when possible.
 | ||||||
|  |     Memory::ReadBlock(*src_process, src_address, &header.raw, sizeof(header.raw)); | ||||||
|  | 
 | ||||||
|  |     size_t untranslated_size = 1u + header.normal_params_size; | ||||||
|  |     size_t command_size = untranslated_size + header.translate_params_size; | ||||||
|  | 
 | ||||||
|  |     // Note: The real kernel does not check that the command length fits into the IPC buffer area.
 | ||||||
|  |     ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH); | ||||||
|  | 
 | ||||||
|  |     std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; | ||||||
|  |     Memory::ReadBlock(*src_process, src_address, cmd_buf.data(), command_size * sizeof(u32)); | ||||||
|  | 
 | ||||||
|  |     size_t i = untranslated_size; | ||||||
|  |     while (i < command_size) { | ||||||
|  |         u32 descriptor = cmd_buf[i]; | ||||||
|  |         i += 1; | ||||||
|  | 
 | ||||||
|  |         switch (IPC::GetDescriptorType(descriptor)) { | ||||||
|  |         case IPC::DescriptorType::CopyHandle: | ||||||
|  |         case IPC::DescriptorType::MoveHandle: { | ||||||
|  |             u32 num_handles = IPC::HandleNumberFromDesc(descriptor); | ||||||
|  |             // Note: The real kernel does not check that the number of handles fits into the command
 | ||||||
|  |             // buffer before writing them, only after finishing.
 | ||||||
|  |             if (i + num_handles > command_size) { | ||||||
|  |                 return ResultCode(ErrCodes::CommandTooLarge, ErrorModule::OS, | ||||||
|  |                                   ErrorSummary::InvalidState, ErrorLevel::Status); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             for (u32 j = 0; j < num_handles; ++j) { | ||||||
|  |                 Handle handle = cmd_buf[i]; | ||||||
|  |                 SharedPtr<Object> object = nullptr; | ||||||
|  |                 // Perform pseudo-handle detection here because by the time this function is called,
 | ||||||
|  |                 // the current thread and process are no longer the ones which created this IPC
 | ||||||
|  |                 // request, but the ones that are handling it.
 | ||||||
|  |                 if (handle == CurrentThread) { | ||||||
|  |                     object = src_thread; | ||||||
|  |                 } else if (handle == CurrentProcess) { | ||||||
|  |                     object = src_process; | ||||||
|  |                 } else if (handle != 0) { | ||||||
|  |                     object = g_handle_table.GetGeneric(handle); | ||||||
|  |                     if (descriptor == IPC::DescriptorType::MoveHandle) { | ||||||
|  |                         g_handle_table.Close(handle); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (object == nullptr) { | ||||||
|  |                     // Note: The real kernel sets invalid translated handles to 0 in the target
 | ||||||
|  |                     // command buffer.
 | ||||||
|  |                     cmd_buf[i++] = 0; | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 auto result = g_handle_table.Create(std::move(object)); | ||||||
|  |                 cmd_buf[i++] = result.ValueOr(0); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         case IPC::DescriptorType::CallingPid: { | ||||||
|  |             cmd_buf[i++] = src_process->process_id; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         default: | ||||||
|  |             UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Memory::WriteBlock(*dst_thread->owner_process, dst_address, cmd_buf.data(), | ||||||
|  |                        command_size * sizeof(u32)); | ||||||
|  | 
 | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | } // namespace Kernel
 | ||||||
							
								
								
									
										14
									
								
								src/core/hle/kernel/ipc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/core/hle/kernel/ipc.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
|  | 
 | ||||||
|  | namespace Kernel { | ||||||
|  | /// Performs IPC command buffer translation from one process to another.
 | ||||||
|  | ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread> dst_thread, | ||||||
|  |                                   VAddr src_address, VAddr dst_address); | ||||||
|  | } // namespace Kernel
 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue