mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Kernel: Implement svcGetProcessInfo in a basic way
This also adds some basic memory usage accounting. These two types are used by Super Smash Bros. during startup.
This commit is contained in:
		
							parent
							
								
									74d4bc0af1
								
							
						
					
					
						commit
						14eca982f4
					
				
					 6 changed files with 73 additions and 3 deletions
				
			
		|  | @ -172,6 +172,14 @@ template<ResultCode func(u32, s64, s64)> void Wrap() { | ||||||
|     FuncReturn(func(PARAM(0), param1, param2).raw); |     FuncReturn(func(PARAM(0), param1, param2).raw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | template<ResultCode func(s64*, Handle, u32)> void Wrap() { | ||||||
|  |     s64 param_1 = 0; | ||||||
|  |     u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; | ||||||
|  |     Core::g_app_core->SetReg(1, (u32)param_1); | ||||||
|  |     Core::g_app_core->SetReg(2, (u32)(param_1 >> 32)); | ||||||
|  |     FuncReturn(retval); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Function wrappers that return type u32
 | // Function wrappers that return type u32
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -110,6 +110,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { | ||||||
|         auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory, |         auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory, | ||||||
|                 segment.offset, segment.size, memory_state).Unwrap(); |                 segment.offset, segment.size, memory_state).Unwrap(); | ||||||
|         vm_manager.Reprotect(vma, permissions); |         vm_manager.Reprotect(vma, permissions); | ||||||
|  |         misc_memory_used += segment.size; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // Map CodeSet segments
 |     // Map CodeSet segments
 | ||||||
|  | @ -121,6 +122,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { | ||||||
|     vm_manager.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size, |     vm_manager.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size, | ||||||
|             std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, MemoryState::Locked |             std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, MemoryState::Locked | ||||||
|             ).Unwrap(); |             ).Unwrap(); | ||||||
|  |     misc_memory_used += stack_size; | ||||||
| 
 | 
 | ||||||
|     vm_manager.LogLayout(Log::Level::Debug); |     vm_manager.LogLayout(Log::Level::Debug); | ||||||
|     Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); |     Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); | ||||||
|  | @ -162,6 +164,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per | ||||||
|     CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, size, MemoryState::Private)); |     CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, size, MemoryState::Private)); | ||||||
|     vm_manager.Reprotect(vma, perms); |     vm_manager.Reprotect(vma, perms); | ||||||
| 
 | 
 | ||||||
|  |     heap_used += size; | ||||||
|  | 
 | ||||||
|     return MakeResult<VAddr>(heap_end - size); |     return MakeResult<VAddr>(heap_end - size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -173,6 +177,8 @@ ResultCode Process::HeapFree(VAddr target, u32 size) { | ||||||
|     ResultCode result = vm_manager.UnmapRange(target, size); |     ResultCode result = vm_manager.UnmapRange(target, size); | ||||||
|     if (result.IsError()) return result; |     if (result.IsError()) return result; | ||||||
| 
 | 
 | ||||||
|  |     heap_used -= size; | ||||||
|  | 
 | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -206,6 +212,8 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p | ||||||
|     CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, MemoryState::Continuous)); |     CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, MemoryState::Continuous)); | ||||||
|     vm_manager.Reprotect(vma, perms); |     vm_manager.Reprotect(vma, perms); | ||||||
| 
 | 
 | ||||||
|  |     linear_heap_used += size; | ||||||
|  | 
 | ||||||
|     return MakeResult<VAddr>(target); |     return MakeResult<VAddr>(target); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -226,6 +234,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { | ||||||
|     ResultCode result = vm_manager.UnmapRange(target, size); |     ResultCode result = vm_manager.UnmapRange(target, size); | ||||||
|     if (result.IsError()) return result; |     if (result.IsError()) return result; | ||||||
| 
 | 
 | ||||||
|  |     linear_heap_used -= size; | ||||||
|  | 
 | ||||||
|     if (target + size == heap_end) { |     if (target + size == heap_end) { | ||||||
|         // End of linear heap has been freed, so check what's the last allocated block in it and
 |         // End of linear heap has been freed, so check what's the last allocated block in it and
 | ||||||
|         // reduce the size.
 |         // reduce the size.
 | ||||||
|  |  | ||||||
|  | @ -136,6 +136,8 @@ public: | ||||||
|     // The left/right bounds of the address space covered by heap_memory.
 |     // The left/right bounds of the address space covered by heap_memory.
 | ||||||
|     VAddr heap_start = 0, heap_end = 0; |     VAddr heap_start = 0, heap_end = 0; | ||||||
| 
 | 
 | ||||||
|  |     u32 heap_used = 0, linear_heap_used = 0, misc_memory_used = 0; | ||||||
|  | 
 | ||||||
|     MemoryRegionInfo* memory_region = nullptr; |     MemoryRegionInfo* memory_region = nullptr; | ||||||
| 
 | 
 | ||||||
|     /// Bitmask of the used TLS slots
 |     /// Bitmask of the used TLS slots
 | ||||||
|  |  | ||||||
|  | @ -117,6 +117,7 @@ void Thread::Stop() { | ||||||
|     wait_objects.clear(); |     wait_objects.clear(); | ||||||
| 
 | 
 | ||||||
|     Kernel::g_current_process->used_tls_slots[tls_index] = false; |     Kernel::g_current_process->used_tls_slots[tls_index] = false; | ||||||
|  |     g_current_process->misc_memory_used -= Memory::TLS_ENTRY_SIZE; | ||||||
| 
 | 
 | ||||||
|     HLE::Reschedule(__func__); |     HLE::Reschedule(__func__); | ||||||
| } | } | ||||||
|  | @ -414,6 +415,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ASSERT_MSG(thread->tls_index != -1, "Out of TLS space"); |     ASSERT_MSG(thread->tls_index != -1, "Out of TLS space"); | ||||||
|  |     g_current_process->misc_memory_used += Memory::TLS_ENTRY_SIZE; | ||||||
| 
 | 
 | ||||||
|     // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
 |     // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
 | ||||||
|     // to initialize the context
 |     // to initialize the context
 | ||||||
|  | @ -504,7 +506,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| VAddr Thread::GetTLSAddress() const { | VAddr Thread::GetTLSAddress() const { | ||||||
|     return Memory::TLS_AREA_VADDR + tls_index * 0x200; |     return Memory::TLS_AREA_VADDR + tls_index * Memory::TLS_ENTRY_SIZE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  |  | ||||||
|  | @ -774,6 +774,52 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { | ||||||
|  |     LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type); | ||||||
|  | 
 | ||||||
|  |     using Kernel::Process; | ||||||
|  |     Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle); | ||||||
|  |     if (process == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     switch (type) { | ||||||
|  |     case 0: | ||||||
|  |     case 2: | ||||||
|  |         // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
 | ||||||
|  |         // what's the difference between them.
 | ||||||
|  |         *out = process->heap_used + process->linear_heap_used + process->misc_memory_used; | ||||||
|  |         break; | ||||||
|  |     case 1: | ||||||
|  |     case 3: | ||||||
|  |     case 4: | ||||||
|  |     case 5: | ||||||
|  |     case 6: | ||||||
|  |     case 7: | ||||||
|  |     case 8: | ||||||
|  |         // These are valid, but not implemented yet
 | ||||||
|  |         LOG_ERROR(Kernel_SVC, "unimplemented GetProcessInfo type=%u", type); | ||||||
|  |         break; | ||||||
|  |     case 20: | ||||||
|  |         *out = Memory::FCRAM_PADDR - process->GetLinearHeapBase(); | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type); | ||||||
|  | 
 | ||||||
|  |         if (type >= 21 && type <= 23) { | ||||||
|  |             return ResultCode( // 0xE0E01BF4
 | ||||||
|  |                     ErrorDescription::NotImplemented, ErrorModule::OS, | ||||||
|  |                     ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||||||
|  |         } else { | ||||||
|  |             return ResultCode( // 0xD8E007ED
 | ||||||
|  |                     ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, | ||||||
|  |                     ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| namespace { | namespace { | ||||||
|     struct FunctionDef { |     struct FunctionDef { | ||||||
|         using Func = void(); |         using Func = void(); | ||||||
|  | @ -828,7 +874,7 @@ static const FunctionDef SVC_Table[] = { | ||||||
|     {0x28, HLE::Wrap<GetSystemTick>,        "GetSystemTick"}, |     {0x28, HLE::Wrap<GetSystemTick>,        "GetSystemTick"}, | ||||||
|     {0x29, nullptr,                         "GetHandleInfo"}, |     {0x29, nullptr,                         "GetHandleInfo"}, | ||||||
|     {0x2A, nullptr,                         "GetSystemInfo"}, |     {0x2A, nullptr,                         "GetSystemInfo"}, | ||||||
|     {0x2B, nullptr,                         "GetProcessInfo"}, |     {0x2B, HLE::Wrap<GetProcessInfo>,       "GetProcessInfo"}, | ||||||
|     {0x2C, nullptr,                         "GetThreadInfo"}, |     {0x2C, nullptr,                         "GetThreadInfo"}, | ||||||
|     {0x2D, HLE::Wrap<ConnectToPort>,        "ConnectToPort"}, |     {0x2D, HLE::Wrap<ConnectToPort>,        "ConnectToPort"}, | ||||||
|     {0x2E, nullptr,                         "SendSyncRequest1"}, |     {0x2E, nullptr,                         "SendSyncRequest1"}, | ||||||
|  |  | ||||||
|  | @ -105,9 +105,11 @@ enum : VAddr { | ||||||
|     // hardcoded value.
 |     // hardcoded value.
 | ||||||
|     /// Area where TLS (Thread-Local Storage) buffers are allocated.
 |     /// Area where TLS (Thread-Local Storage) buffers are allocated.
 | ||||||
|     TLS_AREA_VADDR     = 0x1FF82000, |     TLS_AREA_VADDR     = 0x1FF82000, | ||||||
|     TLS_AREA_SIZE      = 0x00030000, // Each TLS buffer is 0x200 bytes, allows for 300 threads
 |     TLS_ENTRY_SIZE     = 0x200, | ||||||
|  |     TLS_AREA_SIZE      = 300 * TLS_ENTRY_SIZE, // Allows for up to 300 threads
 | ||||||
|     TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, |     TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
 |     /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
 | ||||||
|     NEW_LINEAR_HEAP_VADDR     = 0x30000000, |     NEW_LINEAR_HEAP_VADDR     = 0x30000000, | ||||||
|     NEW_LINEAR_HEAP_SIZE      = 0x10000000, |     NEW_LINEAR_HEAP_SIZE      = 0x10000000, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue