mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge branch 'threading' of https://github.com/bunnei/citra
Conflicts: src/core/hle/function_wrappers.h src/core/hle/service/gsp.cpp
This commit is contained in:
		
						commit
						004df76795
					
				
					 41 changed files with 1279 additions and 1235 deletions
				
			
		|  | @ -48,7 +48,7 @@ void DisassemblerWidget::Init() | ||||||
|     unsigned int curInstAddr = base_addr; |     unsigned int curInstAddr = base_addr; | ||||||
|     char result[255]; |     char result[255]; | ||||||
| 
 | 
 | ||||||
|     for (int i = 0; i < 10000; i++) // fixed for now
 |     for (int i = 0; i < 20000; i++) // fixed for now
 | ||||||
|     { |     { | ||||||
|         disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result); |         disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result); | ||||||
|         model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0')))); |         model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0')))); | ||||||
|  |  | ||||||
|  | @ -259,14 +259,17 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) | ||||||
| 
 | 
 | ||||||
|     switch (Level) |     switch (Level) | ||||||
|     { |     { | ||||||
|  |     case OS_LEVEL: // light yellow
 | ||||||
|  |         Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; | ||||||
|  |         break; | ||||||
|     case NOTICE_LEVEL: // light green
 |     case NOTICE_LEVEL: // light green
 | ||||||
|         Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; |         Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; | ||||||
|         break; |         break; | ||||||
|     case ERROR_LEVEL: // light red
 |     case ERROR_LEVEL: // light red
 | ||||||
|         Color = FOREGROUND_RED | FOREGROUND_INTENSITY; |         Color = FOREGROUND_RED | FOREGROUND_INTENSITY; | ||||||
|         break; |         break; | ||||||
|     case WARNING_LEVEL: // light yellow
 |     case WARNING_LEVEL: // light purple
 | ||||||
|         Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; |         Color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; | ||||||
|         break; |         break; | ||||||
|     case INFO_LEVEL: // cyan
 |     case INFO_LEVEL: // cyan
 | ||||||
|         Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; |         Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; | ||||||
|  | @ -278,15 +281,8 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) | ||||||
|         Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; |         Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     if (strlen(Text) > 10) |  | ||||||
|     { |  | ||||||
|         // First 10 chars white
 |  | ||||||
|         SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); |  | ||||||
|         WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL); |  | ||||||
|         Text += 10; |  | ||||||
|     } |  | ||||||
|     SetConsoleTextAttribute(hConsole, Color); |     SetConsoleTextAttribute(hConsole, Color); | ||||||
|     WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL); |     printf(Text); | ||||||
| #else | #else | ||||||
|     char ColorAttr[16] = ""; |     char ColorAttr[16] = ""; | ||||||
|     char ResetAttr[16] = ""; |     char ResetAttr[16] = ""; | ||||||
|  |  | ||||||
|  | @ -7,11 +7,14 @@ | ||||||
| 
 | 
 | ||||||
| #define LOGGING | #define LOGGING | ||||||
| 
 | 
 | ||||||
| #define    NOTICE_LEVEL  1  // VERY important information that is NOT errors. Like startup and OSReports.
 | enum { | ||||||
| #define    ERROR_LEVEL   2  // Critical errors 
 |     OS_LEVEL,       // Printed by the emulated operating system
 | ||||||
| #define    WARNING_LEVEL 3  // Something is suspicious.
 |     NOTICE_LEVEL,   // VERY important information that is NOT errors. Like startup and OSReports.
 | ||||||
| #define    INFO_LEVEL    4  // General information.
 |     ERROR_LEVEL,    // Critical errors 
 | ||||||
| #define    DEBUG_LEVEL   5  // Detailed debugging - might make things slow.
 |     WARNING_LEVEL,  // Something is suspicious.
 | ||||||
|  |     INFO_LEVEL,     // General information.
 | ||||||
|  |     DEBUG_LEVEL,    // Detailed debugging - might make things slow.
 | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| namespace LogTypes | namespace LogTypes | ||||||
| { | { | ||||||
|  | @ -70,6 +73,7 @@ enum LOG_TYPE { | ||||||
| 
 | 
 | ||||||
| // FIXME: should this be removed?
 | // FIXME: should this be removed?
 | ||||||
| enum LOG_LEVELS { | enum LOG_LEVELS { | ||||||
|  |     LOS = OS_LEVEL, | ||||||
|     LNOTICE = NOTICE_LEVEL, |     LNOTICE = NOTICE_LEVEL, | ||||||
|     LERROR = ERROR_LEVEL, |     LERROR = ERROR_LEVEL, | ||||||
|     LWARNING = WARNING_LEVEL, |     LWARNING = WARNING_LEVEL, | ||||||
|  | @ -82,31 +86,34 @@ enum LOG_LEVELS { | ||||||
| 
 | 
 | ||||||
| }  // namespace
 | }  // namespace
 | ||||||
| 
 | 
 | ||||||
| void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, | void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line,  | ||||||
|         const char *file, int line, const char *fmt, ...) |     const char* function, const char* fmt, ...) | ||||||
| #ifdef __GNUC__ | #ifdef __GNUC__ | ||||||
|         __attribute__((format(printf, 5, 6))) |         __attribute__((format(printf, 6, 7))) | ||||||
| #endif | #endif | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
| #if defined LOGGING || defined _DEBUG || defined DEBUGFAST | #if defined LOGGING || defined _DEBUG || defined DEBUGFAST | ||||||
| #define MAX_LOGLEVEL DEBUG_LEVEL | #define MAX_LOGLEVEL LDEBUG | ||||||
| #else | #else | ||||||
| #ifndef MAX_LOGLEVEL | #ifndef MAX_LOGLEVEL | ||||||
| #define MAX_LOGLEVEL WARNING_LEVEL | #define MAX_LOGLEVEL LWARNING | ||||||
| #endif // loglevel
 | #endif // loglevel
 | ||||||
| #endif // logging
 | #endif // logging
 | ||||||
| 
 | 
 | ||||||
| #ifdef GEKKO | #ifdef _WIN32 | ||||||
| #define GENERIC_LOG(t, v, ...) | #ifndef __func__ | ||||||
| #else | #define __func__ __FUNCTION__ | ||||||
| // Let the compiler optimize this out
 | #endif | ||||||
| #define GENERIC_LOG(t, v, ...) { \ |  | ||||||
|     if (v <= MAX_LOGLEVEL) \ |  | ||||||
|         GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ |  | ||||||
|     } |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | // Let the compiler optimize this out
 | ||||||
|  | #define GENERIC_LOG(t, v, ...) { \ | ||||||
|  |     if (v <= LogTypes::MAX_LOGLEVEL) \ | ||||||
|  |         GenericLog(v, t, __FILE__, __LINE__, __func__, __VA_ARGS__); \ | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | #define OS_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LOS, __VA_ARGS__) } while (0) | ||||||
| #define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) | #define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) | ||||||
| #define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) | #define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) | ||||||
| #define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) | #define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) | ||||||
|  |  | ||||||
|  | @ -10,14 +10,16 @@ | ||||||
| #include "common/thread.h" | #include "common/thread.h" | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| 
 | 
 | ||||||
| void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,  | void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,  | ||||||
|         const char *file, int line, const char* fmt, ...) |     const char* function, const char* fmt, ...) | ||||||
| { | { | ||||||
|     va_list args; |     va_list args; | ||||||
|     va_start(args, fmt); |     va_start(args, fmt); | ||||||
|     if (LogManager::GetInstance()) | 
 | ||||||
|  |     if (LogManager::GetInstance()) { | ||||||
|         LogManager::GetInstance()->Log(level, type, |         LogManager::GetInstance()->Log(level, type, | ||||||
|             file, line, fmt, args); |             file, line, function, fmt, args); | ||||||
|  |     } | ||||||
|     va_end(args); |     va_end(args); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -88,6 +90,8 @@ LogManager::LogManager() | ||||||
|             m_Log[i]->AddListener(m_debuggerLog); |             m_Log[i]->AddListener(m_debuggerLog); | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     m_consoleLog->Open(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| LogManager::~LogManager() | LogManager::~LogManager() | ||||||
|  | @ -107,8 +111,8 @@ LogManager::~LogManager() | ||||||
|     delete m_debuggerLog; |     delete m_debuggerLog; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,  | void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file,  | ||||||
|     const char *file, int line, const char *format, va_list args) |     int line, const char* function, const char *fmt, va_list args) | ||||||
| { | { | ||||||
|     char temp[MAX_MSGLEN]; |     char temp[MAX_MSGLEN]; | ||||||
|     char msg[MAX_MSGLEN * 2]; |     char msg[MAX_MSGLEN * 2]; | ||||||
|  | @ -117,17 +121,15 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, | ||||||
|     if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) |     if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); |     CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args); | ||||||
|  | 
 | ||||||
|  |     static const char level_to_char[7] = "ONEWID"; | ||||||
|  |     sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line,  | ||||||
|  |         level_to_char[(int)level], log->GetShortName(), function, temp); | ||||||
|      |      | ||||||
|     static const char level_to_char[7] = "-NEWID"; |  | ||||||
|     sprintf(msg, "%s %s:%u %c[%s]: %s\n", |  | ||||||
|         Common::Timer::GetTimeFormatted().c_str(), |  | ||||||
|         file, line, level_to_char[(int)level], |  | ||||||
|         log->GetShortName(), temp); |  | ||||||
| #ifdef ANDROID | #ifdef ANDROID | ||||||
|     Host_SysMessage(msg);     |     Host_SysMessage(msg);     | ||||||
| #endif | #endif | ||||||
|     printf(msg); // TODO(ShizZy): RemoveMe when I no longer need this
 |  | ||||||
|     log->Trigger(level, msg); |     log->Trigger(level, msg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -147,7 +149,7 @@ LogContainer::LogContainer(const char* shortName, const char* fullName, bool ena | ||||||
| { | { | ||||||
|     strncpy(m_fullName, fullName, 128); |     strncpy(m_fullName, fullName, 128); | ||||||
|     strncpy(m_shortName, shortName, 32); |     strncpy(m_shortName, shortName, 32); | ||||||
|     m_level = (LogTypes::LOG_LEVELS)MAX_LOGLEVEL; |     m_level = LogTypes::MAX_LOGLEVEL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // LogContainer
 | // LogContainer
 | ||||||
|  |  | ||||||
|  | @ -97,10 +97,10 @@ private: | ||||||
|     ~LogManager(); |     ~LogManager(); | ||||||
| public: | public: | ||||||
| 
 | 
 | ||||||
|     static u32 GetMaxLevel() { return MAX_LOGLEVEL;    } |     static u32 GetMaxLevel() { return LogTypes::MAX_LOGLEVEL;    } | ||||||
| 
 | 
 | ||||||
|     void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,  |     void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,  | ||||||
|              const char *file, int line, const char *fmt, va_list args); |         const char* function, const char *fmt, va_list args); | ||||||
| 
 | 
 | ||||||
|     void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) |     void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  | @ -34,12 +34,14 @@ set(SRCS    core.cpp | ||||||
|             hle/config_mem.cpp |             hle/config_mem.cpp | ||||||
|             hle/coprocessor.cpp |             hle/coprocessor.cpp | ||||||
|             hle/svc.cpp |             hle/svc.cpp | ||||||
|  |             hle/kernel/event.cpp | ||||||
|             hle/kernel/kernel.cpp |             hle/kernel/kernel.cpp | ||||||
|             hle/kernel/mutex.cpp |             hle/kernel/mutex.cpp | ||||||
|             hle/kernel/thread.cpp |             hle/kernel/thread.cpp | ||||||
|             hle/service/apt.cpp |             hle/service/apt.cpp | ||||||
|             hle/service/gsp.cpp |             hle/service/gsp.cpp | ||||||
|             hle/service/hid.cpp |             hle/service/hid.cpp | ||||||
|  |             hle/service/ndm.cpp | ||||||
|             hle/service/service.cpp |             hle/service/service.cpp | ||||||
|             hle/service/srv.cpp |             hle/service/srv.cpp | ||||||
|             hw/gpu.cpp |             hw/gpu.cpp | ||||||
|  |  | ||||||
|  | @ -89,6 +89,9 @@ public: | ||||||
|      */ |      */ | ||||||
|     virtual void LoadContext(const ThreadContext& ctx) = 0; |     virtual void LoadContext(const ThreadContext& ctx) = 0; | ||||||
| 
 | 
 | ||||||
|  |     /// Prepare core for thread reschedule (if needed to correctly handle state)
 | ||||||
|  |     virtual void PrepareReschedule() = 0; | ||||||
|  | 
 | ||||||
|     /// Getter for num_instructions
 |     /// Getter for num_instructions
 | ||||||
|     u64 GetNumInstructions() { |     u64 GetNumInstructions() { | ||||||
|         return num_instructions; |         return num_instructions; | ||||||
|  |  | ||||||
|  | @ -98,7 +98,7 @@ u64 ARM_Interpreter::GetTicks() const { | ||||||
|  * @param num_instructions Number of instructions to executes |  * @param num_instructions Number of instructions to executes | ||||||
|  */ |  */ | ||||||
| void ARM_Interpreter::ExecuteInstructions(int num_instructions) { | void ARM_Interpreter::ExecuteInstructions(int num_instructions) { | ||||||
|     state->NumInstrsToExecute = num_instructions; |     state->NumInstrsToExecute = num_instructions - 1; | ||||||
|     ARMul_Emulate32(state); |     ARMul_Emulate32(state); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -118,6 +118,9 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     ctx.fpscr = state->VFP[1]; |     ctx.fpscr = state->VFP[1]; | ||||||
|     ctx.fpexc = state->VFP[2]; |     ctx.fpexc = state->VFP[2]; | ||||||
|  | 
 | ||||||
|  |     ctx.reg_15 = state->Reg[15]; | ||||||
|  |     ctx.mode = state->NextInstr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -137,6 +140,11 @@ void ARM_Interpreter::LoadContext(const ThreadContext& ctx) { | ||||||
|     state->VFP[1] = ctx.fpscr; |     state->VFP[1] = ctx.fpscr; | ||||||
|     state->VFP[2] = ctx.fpexc; |     state->VFP[2] = ctx.fpexc; | ||||||
| 
 | 
 | ||||||
|     state->Reg[15] = ctx.pc; |     state->Reg[15] = ctx.reg_15; | ||||||
|     state->NextInstr = RESUME; |     state->NextInstr = ctx.mode; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Prepare core for thread reschedule (if needed to correctly handle state)
 | ||||||
|  | void ARM_Interpreter::PrepareReschedule() { | ||||||
|  |     state->NumInstrsToExecute = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -72,6 +72,9 @@ public: | ||||||
|      */ |      */ | ||||||
|     void LoadContext(const ThreadContext& ctx); |     void LoadContext(const ThreadContext& ctx); | ||||||
| 
 | 
 | ||||||
|  |     /// Prepare core for thread reschedule (if needed to correctly handle state)
 | ||||||
|  |     void PrepareReschedule(); | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  |  | ||||||
|  | @ -4456,6 +4456,7 @@ ARMul_Emulate26 (ARMul_State * state) | ||||||
|                     } |                     } | ||||||
|                 /* Drop through.  */ |                 /* Drop through.  */ | ||||||
| 
 | 
 | ||||||
|  |             case 0xe0: | ||||||
|             case 0xe4: |             case 0xe4: | ||||||
|             case 0xe6: |             case 0xe6: | ||||||
|             case 0xe8: |             case 0xe8: | ||||||
|  | @ -4489,7 +4490,6 @@ ARMul_Emulate26 (ARMul_State * state) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|                 /* Co-Processor Register Transfers (MRC) and Data Ops.  */ |                 /* Co-Processor Register Transfers (MRC) and Data Ops.  */ | ||||||
|             case 0xe0: |  | ||||||
|             case 0xe1: |             case 0xe1: | ||||||
|             case 0xe3: |             case 0xe3: | ||||||
|             case 0xe5: |             case 0xe5: | ||||||
|  | @ -4533,23 +4533,7 @@ ARMul_Emulate26 (ARMul_State * state) | ||||||
|             case 0xfd: |             case 0xfd: | ||||||
|             case 0xfe: |             case 0xfe: | ||||||
|             case 0xff: |             case 0xff: | ||||||
|                 if (instr == ARMul_ABORTWORD |  | ||||||
|                     && state->AbortAddr == pc) { |  | ||||||
|                     /* A prefetch abort.  */ |  | ||||||
|                     XScale_set_fsr_far (state, |  | ||||||
|                                 ARMul_CP15_R5_MMU_EXCPT, |  | ||||||
|                                 pc); |  | ||||||
|                     ARMul_Abort (state, |  | ||||||
|                              ARMul_PrefetchAbortV); |  | ||||||
|                     break; |  | ||||||
|                 } |  | ||||||
|                 //sky_pref_t* pref = get_skyeye_pref();
 |  | ||||||
|                 //if(pref->user_mode_sim){
 |  | ||||||
|                 //    ARMul_OSHandleSWI (state, BITS (0, 23));
 |  | ||||||
|                 //    break;
 |  | ||||||
|                 //}
 |  | ||||||
|                 HLE::CallSVC(instr); |                 HLE::CallSVC(instr); | ||||||
|                 ARMul_Abort (state, ARMul_SWIV); |  | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -9,21 +9,24 @@ | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/mem_map.h" | #include "core/mem_map.h" | ||||||
| #include "core/hw/hw.h" | #include "core/hw/hw.h" | ||||||
|  | #include "core/hw/gpu.h" | ||||||
| #include "core/arm/disassembler/arm_disasm.h" | #include "core/arm/disassembler/arm_disasm.h" | ||||||
| #include "core/arm/interpreter/arm_interpreter.h" | #include "core/arm/interpreter/arm_interpreter.h" | ||||||
| 
 | 
 | ||||||
|  | #include "core/hle/hle.h" | ||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
| 
 | 
 | ||||||
| namespace Core { | namespace Core { | ||||||
| 
 | 
 | ||||||
| ARM_Disasm*     g_disasm    = NULL; ///< ARM disassembler
 | u64             g_last_ticks    = 0;        ///< Last CPU ticks
 | ||||||
| ARM_Interface*  g_app_core  = NULL; ///< ARM11 application core
 | ARM_Disasm*     g_disasm        = nullptr;  ///< ARM disassembler
 | ||||||
| ARM_Interface*  g_sys_core  = NULL; ///< ARM11 system (OS) core
 | ARM_Interface*  g_app_core      = nullptr;  ///< ARM11 application core
 | ||||||
|  | ARM_Interface*  g_sys_core      = nullptr;  ///< ARM11 system (OS) core
 | ||||||
| 
 | 
 | ||||||
| /// Run the core CPU loop
 | /// Run the core CPU loop
 | ||||||
| void RunLoop() { | void RunLoop() { | ||||||
|     for (;;){ |     for (;;){ | ||||||
|         g_app_core->Run(100); |         g_app_core->Run(GPU::kFrameTicks); | ||||||
|         HW::Update(); |         HW::Update(); | ||||||
|         Kernel::Reschedule(); |         Kernel::Reschedule(); | ||||||
|     } |     } | ||||||
|  | @ -32,9 +35,15 @@ void RunLoop() { | ||||||
| /// Step the CPU one instruction
 | /// Step the CPU one instruction
 | ||||||
| void SingleStep() { | void SingleStep() { | ||||||
|     g_app_core->Step(); |     g_app_core->Step(); | ||||||
|  | 
 | ||||||
|  |     // Update and reschedule after approx. 1 frame
 | ||||||
|  |     u64 current_ticks = Core::g_app_core->GetTicks(); | ||||||
|  |     if ((current_ticks - g_last_ticks) >= GPU::kFrameTicks || HLE::g_reschedule) { | ||||||
|  |         g_last_ticks = current_ticks; | ||||||
|         HW::Update(); |         HW::Update(); | ||||||
|         Kernel::Reschedule(); |         Kernel::Reschedule(); | ||||||
|     } |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /// Halt the core
 | /// Halt the core
 | ||||||
| void Halt(const char *msg) { | void Halt(const char *msg) { | ||||||
|  | @ -54,6 +63,8 @@ int Init() { | ||||||
|     g_app_core = new ARM_Interpreter(); |     g_app_core = new ARM_Interpreter(); | ||||||
|     g_sys_core = new ARM_Interpreter(); |     g_sys_core = new ARM_Interpreter(); | ||||||
| 
 | 
 | ||||||
|  |     g_last_ticks = Core::g_app_core->GetTicks(); | ||||||
|  | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -168,12 +168,14 @@ | ||||||
|     <ClCompile Include="hle\config_mem.cpp" /> |     <ClCompile Include="hle\config_mem.cpp" /> | ||||||
|     <ClCompile Include="hle\coprocessor.cpp" /> |     <ClCompile Include="hle\coprocessor.cpp" /> | ||||||
|     <ClCompile Include="hle\hle.cpp" /> |     <ClCompile Include="hle\hle.cpp" /> | ||||||
|  |     <ClCompile Include="hle\kernel\event.cpp" /> | ||||||
|     <ClCompile Include="hle\kernel\kernel.cpp" /> |     <ClCompile Include="hle\kernel\kernel.cpp" /> | ||||||
|     <ClCompile Include="hle\kernel\mutex.cpp" /> |     <ClCompile Include="hle\kernel\mutex.cpp" /> | ||||||
|     <ClCompile Include="hle\kernel\thread.cpp" /> |     <ClCompile Include="hle\kernel\thread.cpp" /> | ||||||
|     <ClCompile Include="hle\service\apt.cpp" /> |     <ClCompile Include="hle\service\apt.cpp" /> | ||||||
|     <ClCompile Include="hle\service\gsp.cpp" /> |     <ClCompile Include="hle\service\gsp.cpp" /> | ||||||
|     <ClCompile Include="hle\service\hid.cpp" /> |     <ClCompile Include="hle\service\hid.cpp" /> | ||||||
|  |     <ClCompile Include="hle\service\ndm.cpp" /> | ||||||
|     <ClCompile Include="hle\service\service.cpp" /> |     <ClCompile Include="hle\service\service.cpp" /> | ||||||
|     <ClCompile Include="hle\service\srv.cpp" /> |     <ClCompile Include="hle\service\srv.cpp" /> | ||||||
|     <ClCompile Include="hle\svc.cpp" /> |     <ClCompile Include="hle\svc.cpp" /> | ||||||
|  | @ -217,12 +219,14 @@ | ||||||
|     <ClInclude Include="hle\coprocessor.h" /> |     <ClInclude Include="hle\coprocessor.h" /> | ||||||
|     <ClInclude Include="hle\function_wrappers.h" /> |     <ClInclude Include="hle\function_wrappers.h" /> | ||||||
|     <ClInclude Include="hle\hle.h" /> |     <ClInclude Include="hle\hle.h" /> | ||||||
|  |     <ClInclude Include="hle\kernel\event.h" /> | ||||||
|     <ClInclude Include="hle\kernel\kernel.h" /> |     <ClInclude Include="hle\kernel\kernel.h" /> | ||||||
|     <ClInclude Include="hle\kernel\mutex.h" /> |     <ClInclude Include="hle\kernel\mutex.h" /> | ||||||
|     <ClInclude Include="hle\kernel\thread.h" /> |     <ClInclude Include="hle\kernel\thread.h" /> | ||||||
|     <ClInclude Include="hle\service\apt.h" /> |     <ClInclude Include="hle\service\apt.h" /> | ||||||
|     <ClInclude Include="hle\service\gsp.h" /> |     <ClInclude Include="hle\service\gsp.h" /> | ||||||
|     <ClInclude Include="hle\service\hid.h" /> |     <ClInclude Include="hle\service\hid.h" /> | ||||||
|  |     <ClInclude Include="hle\service\ndm.h" /> | ||||||
|     <ClInclude Include="hle\service\service.h" /> |     <ClInclude Include="hle\service\service.h" /> | ||||||
|     <ClInclude Include="hle\service\srv.h" /> |     <ClInclude Include="hle\service\srv.h" /> | ||||||
|     <ClInclude Include="hle\svc.h" /> |     <ClInclude Include="hle\svc.h" /> | ||||||
|  |  | ||||||
|  | @ -165,6 +165,12 @@ | ||||||
|     <ClCompile Include="arm\interpreter\armcopro.cpp"> |     <ClCompile Include="arm\interpreter\armcopro.cpp"> | ||||||
|       <Filter>arm\interpreter</Filter> |       <Filter>arm\interpreter</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="hle\kernel\event.cpp"> | ||||||
|  |       <Filter>hle\kernel</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="hle\service\ndm.cpp"> | ||||||
|  |       <Filter>hle\service</Filter> | ||||||
|  |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClInclude Include="arm\disassembler\arm_disasm.h"> |     <ClInclude Include="arm\disassembler\arm_disasm.h"> | ||||||
|  | @ -295,6 +301,12 @@ | ||||||
|     <ClInclude Include="hle\kernel\mutex.h"> |     <ClInclude Include="hle\kernel\mutex.h"> | ||||||
|       <Filter>hle\kernel</Filter> |       <Filter>hle\kernel</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="hle\kernel\event.h"> | ||||||
|  |       <Filter>hle\kernel</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="hle\service\ndm.h"> | ||||||
|  |       <Filter>hle\service</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <Text Include="CMakeLists.txt" /> |     <Text Include="CMakeLists.txt" /> | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ inline void Read(T &var, const u32 addr) { | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     default: |     default: | ||||||
|         ERROR_LOG(HLE, "unknown ConfigMem::Read%d @ 0x%08X", sizeof(var) * 8, addr); |         ERROR_LOG(HLE, "unknown addr=0x%08X", addr); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,7 +25,7 @@ s32 CallMRC(u32 instruction) { | ||||||
|         return GetThreadCommandBuffer(); |         return GetThreadCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     default: |     default: | ||||||
|         //DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction);
 |         DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     return -1; |     return -1; | ||||||
|  |  | ||||||
|  | @ -1,19 +1,6 @@ | ||||||
| // Copyright (c) 2012- PPSSPP Project.
 | // Copyright 2014 Citra Emulator Project
 | ||||||
| 
 | // Licensed under GPLv2
 | ||||||
| // This program is free software: you can redistribute it and/or modify
 | // Refer to the license.txt file included.
 | ||||||
| // it under the terms of the GNU General Public License as published by
 |  | ||||||
| // the Free Software Foundation, version 2.0 or later versions.
 |  | ||||||
| 
 |  | ||||||
| // This program is distributed in the hope that it will be useful,
 |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 |  | ||||||
| // GNU General Public License 2.0 for more details.
 |  | ||||||
| 
 |  | ||||||
| // A copy of the GPL 2.0 should have been included with the program.
 |  | ||||||
| // If not, see http://www.gnu.org/licenses/
 |  | ||||||
| 
 |  | ||||||
| // Official git repository and contact information can be found at
 |  | ||||||
| // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 |  | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | @ -21,725 +8,107 @@ | ||||||
| #include "core/mem_map.h" | #include "core/mem_map.h" | ||||||
| #include "core/hle/hle.h" | #include "core/hle/hle.h" | ||||||
| 
 | 
 | ||||||
| // For easy parameter parsing and return value processing.
 | namespace HLE { | ||||||
| 
 | 
 | ||||||
| //32bit wrappers
 | #define PARAM(n)    Core::g_app_core->GetReg(n) | ||||||
| template<void func()> void WrapV_V() { | #define RETURN(n)   Core::g_app_core->SetReg(0, n) | ||||||
|     func(); | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Function wrappers that return type s32
 | ||||||
|  | 
 | ||||||
|  | template<s32 func(u32, u32, u32, u32)> void Wrap() { | ||||||
|  |     RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<u32 func()> void WrapU_V() { | template<s32 func(u32, u32, u32, u32, u32)> void Wrap() { | ||||||
|  |     RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(u32*, u32, u32, u32, u32, u32)> void Wrap(){ | ||||||
|  |     u32 param_1 = 0; | ||||||
|  |     u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||||||
|  |     Core::g_app_core->SetReg(1, param_1); | ||||||
|  |     RETURN(retval); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() { | ||||||
|  |     s32 param_1 = 0; | ||||||
|  |     s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),  | ||||||
|  |         (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))); | ||||||
|  |     Core::g_app_core->SetReg(1, (u32)param_1); | ||||||
|  |     RETURN(retval); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TODO(bunnei): Is this correct? Probably not
 | ||||||
|  | template<s32 func(u32, u32, u32, u32, s64)> void Wrap() { | ||||||
|  |     RETURN(func(PARAM(5), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(4) << 32) | PARAM(0)))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(u32, s64)> void Wrap() { | ||||||
|  |     RETURN(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2)))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(void*, void*, u32)> void Wrap(){ | ||||||
|  |     RETURN(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(s32*, u32)> void Wrap(){ | ||||||
|  |     s32 param_1 = 0; | ||||||
|  |     u32 retval = func(¶m_1, PARAM(1)); | ||||||
|  |     Core::g_app_core->SetReg(1, param_1); | ||||||
|  |     RETURN(retval); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(u32, s32)> void Wrap() { | ||||||
|  |     RETURN(func(PARAM(0), (s32)PARAM(1))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(u32*, u32)> void Wrap(){ | ||||||
|  |     u32 param_1 = 0; | ||||||
|  |     u32 retval = func(¶m_1, PARAM(1)); | ||||||
|  |     Core::g_app_core->SetReg(1, param_1); | ||||||
|  |     RETURN(retval); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(u32)> void Wrap() { | ||||||
|  |     RETURN(func(PARAM(0))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(void*)> void Wrap() { | ||||||
|  |     RETURN(func(Memory::GetPointer(PARAM(0)))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(s64*, u32, void*, s32)> void Wrap(){ | ||||||
|  |     RETURN(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)),  | ||||||
|  |         (s32)PARAM(3))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<s32 func(u32*, const char*)> void Wrap() { | ||||||
|  |     u32 param_1 = 0; | ||||||
|  |     u32 retval = func(¶m_1, Memory::GetCharPointer(PARAM(1))); | ||||||
|  |     Core::g_app_core->SetReg(1, param_1); | ||||||
|  |     RETURN(retval); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Function wrappers that return type u32
 | ||||||
|  | 
 | ||||||
|  | template<u32 func()> void Wrap() { | ||||||
|     RETURN(func()); |     RETURN(func()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<int func(void *, const char *)> void WrapI_VC() { | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|     u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1))); | /// Function wrappers that return type void
 | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, void *, int)> void WrapU_IVI() { |  | ||||||
|     u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, int, int, u32)> void WrapI_CIIU() { |  | ||||||
|     u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, const char *, u32, void *, void *, u32, int)> void WrapI_ICUVVUI() { |  | ||||||
|     u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)),Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) ); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Hm, do so many params get passed in registers?
 |  | ||||||
| template<int func(const char *, int, const char *, int, int, int, int, int)> void WrapI_CICIIIII() { |  | ||||||
|     u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), Memory::GetCharPointer(PARAM(2)), |  | ||||||
|         PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Hm, do so many params get passed in registers?
 |  | ||||||
| template<int func(const char *, int, int, int, int, int, int)> void WrapI_CIIIIII() { |  | ||||||
|     u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), |  | ||||||
|         PARAM(3), PARAM(4), PARAM(5), PARAM(6)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Hm, do so many params get passed in registers?
 |  | ||||||
| template<int func(int, int, int, int, int, int, u32)> void WrapI_IIIIIIU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Hm, do so many params get passed in registers?
 |  | ||||||
| template<int func(int, int, int, int, int, int, int, int, u32)> void WrapI_IIIIIIIIU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7), PARAM(8)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, void *)> void WrapU_IV() { |  | ||||||
|     u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1))); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32)> void WrapU_U() { |  | ||||||
|     u32 retval = func(PARAM(0)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int)> void WrapU_UI() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32)> void WrapI_U() { |  | ||||||
|     int retval = func(PARAM(0)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, int)> void WrapI_UI() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, int, int, u32)> void WrapI_UIIU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, u32, int)> void WrapU_IUI() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32)> void WrapI_UU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32, u32)> void WrapI_UUU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32, u32, int)> void WrapI_UUUI() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32, u32, int, int, int,int )> void WrapI_UUUIIII() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32, u32, u32)> void WrapI_UUUU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32, u32, u32, u32)> void WrapI_UUUUU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(void*)> void WrapI_V() { |  | ||||||
|     u32 retval = func(Memory::GetPointer(PARAM(0))); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int)> void WrapU_I() { |  | ||||||
|     u32 retval = func(PARAM(0)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, int, u32)> void WrapU_IIU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int)> void WrapI_I() { |  | ||||||
|     int retval = func(PARAM(0)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32)> void WrapV_U() { |  | ||||||
|     func(PARAM(0)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(int)> void WrapV_I() { |  | ||||||
|     func(PARAM(0)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, u32)> void WrapV_UU() { |  | ||||||
|     func(PARAM(0), PARAM(1)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(int, int)> void WrapV_II() { |  | ||||||
|     func(PARAM(0), PARAM(1)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, const char *)> void WrapV_UC() { |  | ||||||
|     func(PARAM(0), Memory::GetCharPointer(PARAM(1))); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, const char *)> void WrapI_UC() { |  | ||||||
|     int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1))); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, const char *, int)> void WrapI_UCI() { |  | ||||||
|     int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int , int , int, int, int)> void WrapU_UIIIII() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int , int , int, u32)> void WrapU_UIIIU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32)> void WrapU_UU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, int)> void WrapU_UUI() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, int, int)> void WrapU_UUII() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(const char *, u32, u32, u32)> void WrapU_CUUU() { |  | ||||||
|     u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, int, u32, int, int)> void WrapV_UIUII() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int, u32, int, int)> void WrapU_UIUII() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, int, u32, int, int)> void WrapI_UIUII() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int, u32, int)> void WrapU_UIUI() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, int, u32, int)> void WrapI_UIUI() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int, u32)> void WrapU_UIU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int, u32, u32)> void WrapU_UIUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int, int)> void WrapU_UII() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int, int, u32)> void WrapU_UIIU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, int, int, u32, u32)> void WrapI_UIIUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32, int, int)> void WrapI_UUII() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32, int, int, int)> void WrapI_UUIII() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, int, int, int)> void WrapV_UIII() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, int, int, int, int, int)> void WrapV_UIIIII() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, int, int)> void WrapV_UII() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, u32)> void WrapU_IU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, u32)> void WrapI_IU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32, int)> void WrapI_UUI() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, u32, int, u32)> void WrapI_UUIU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, int)> void WrapI_II() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, int, int)> void WrapI_III() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, u32, int)> void WrapI_IUI() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, int, int, int)> void WrapI_IIII() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, int, int, int)> void WrapI_UIII() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, int, int, u32, int)> void WrapI_IIIUI() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, u32, u32, int, int)> void WrapI_IUUII() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, const char *, int, u32, u32)> void WrapI_ICIUU() { |  | ||||||
|     int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, int, u32)> void WrapI_IIU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(int, u32)> void WrapV_IU() { |  | ||||||
|     func(PARAM(0), PARAM(1)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, int)> void WrapV_UI() { |  | ||||||
|     func(PARAM(0), PARAM(1)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(const char *)> void WrapU_C() { |  | ||||||
|     u32 retval = func(Memory::GetCharPointer(PARAM(0))); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(const char *, const char *, const char *, u32)> void WrapU_CCCU() { |  | ||||||
|     u32 retval = func(Memory::GetCharPointer(PARAM(0)), |  | ||||||
|             Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), |  | ||||||
|             PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *)> void WrapI_C() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0))); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, u32)> void WrapI_CU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, u32, int)> void WrapI_CUI() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, const char *, int, u32)> void WrapI_ICIU() { |  | ||||||
|     int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, int, u32)> void WrapI_CIU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, u32, u32)> void WrapI_CUU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, u32, u32, u32)> void WrapI_CUUU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), |  | ||||||
|             PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, const char*, int, int)> void WrapI_CCII() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, u32, u32, int, u32, u32)> void WrapI_CUUIUU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), |  | ||||||
|             PARAM(3), PARAM(4), PARAM(5)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, int, int, u32, int, int)> void WrapI_CIIUII() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), |  | ||||||
|         PARAM(3), PARAM(4), PARAM(5)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, int, u32, u32, u32)> void WrapI_CIUUU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), |  | ||||||
|             PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, u32, u32, u32, u32, u32)> void WrapI_CUUUUU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), |  | ||||||
|             PARAM(3), PARAM(4), PARAM(5)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(const char *, u32)> void WrapU_CU() { |  | ||||||
|     u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); |  | ||||||
|     RETURN((u32) retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, const char *)> void WrapU_UC() { |  | ||||||
|     u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1))); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(const char *, u32, u32)> void WrapU_CUU() { |  | ||||||
|     u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN((u32) retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, int, int)> void WrapU_III() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, int)> void WrapU_II() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, int, int, int)> void WrapU_IIII() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, u32, u32)> void WrapU_IUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, u32, u32, u32)> void WrapU_IUUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(int, u32, u32, u32, u32)> void WrapU_IUUUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, u32)> void WrapU_UUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(int, u32, u32)> void WrapV_IUU() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(int, int, u32)> void WrapV_IIU() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, int, u32)> void WrapV_UIU() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, int, u32)> void WrapI_UIU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(int, u32, u32, u32, u32)> void WrapV_IUUUU() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, u32, u32)> void WrapV_UUU() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, u32, u32, u32)> void WrapV_UUUU() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(const char *, u32, int, u32)> void WrapV_CUIU() { |  | ||||||
|     func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, u32, int, u32)> void WrapI_CUIU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, const char *, u32, int, u32)> void WrapV_UCUIU() { |  | ||||||
|     func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), |  | ||||||
|             PARAM(4)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, const char *, u32, int, u32)> void WrapI_UCUIU() { |  | ||||||
|     int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), |  | ||||||
|             PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(const char *, u32, int, int, u32)> void WrapV_CUIIU() { |  | ||||||
|     func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), |  | ||||||
|             PARAM(4)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, u32, int, int, u32)> void WrapI_CUIIU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), |  | ||||||
|             PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, u32, u32)> void WrapU_UUUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, const char *, u32, u32)> void WrapU_UCUU() { |  | ||||||
|     u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, u32, int, u32)> void WrapU_UUUIU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, u32, int, u32, int)> void WrapU_UUUIUI() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, int, u32)> void WrapU_UUIU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, int, int, int)> void WrapU_UIII() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, u32, u32, u32, u32)> void WrapI_IUUUU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, u32, u32, u32, u32, u32)> void WrapI_IUUUUU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, u32, int, int)> void WrapI_IUII() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| template<u32 func(u32, u32, u32, u32, u32)> void WrapU_UUUUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<void func(u32, u32, u32, u32, u32)> void WrapV_UUUUU() { |  | ||||||
|     func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| template<u32 func(const char *, const char *)> void WrapU_CC() { | template<void func(s64)> void Wrap() { | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), |     func(((s64)PARAM(1) << 32) | PARAM(0)); | ||||||
|             Memory::GetCharPointer(PARAM(1))); |  | ||||||
|     RETURN(retval); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<void func(const char*)> void WrapV_C() { | template<void func(const char*)> void Wrap() { | ||||||
|     func(Memory::GetCharPointer(PARAM(0))); |     func(Memory::GetCharPointer(PARAM(0))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<void func(const char *, int)> void WrapV_CI() { | #undef PARAM | ||||||
|     func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); | #undef RETURN | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| template<u32 func(const char *, int)> void WrapU_CI() { | } // namespace HLE
 | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(const char *, int, int)> void WrapU_CII() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(const char *, int, u32, int, u32)> void WrapU_CIUIU() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), |  | ||||||
|             PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(const char *, int, u32, int, u32, int)> void WrapU_CIUIUI() { |  | ||||||
|     u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), |  | ||||||
|             PARAM(3), PARAM(4), PARAM(5)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), |  | ||||||
|             PARAM(5)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, u32, u32, u32)> void WrapI_IUUU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, u32, u32)> void WrapI_IUU() { |  | ||||||
|     int retval = func(PARAM(0), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<u32 func(u32, u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUUU() { |  | ||||||
|   u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); |  | ||||||
|   RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, int, u32, u32)> void WrapI_UIUU() { |  | ||||||
|     u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, const char *)> void WrapI_IC() { |  | ||||||
|     int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1))); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template <int func(int, const char *, const char *, u32, int)> void WrapI_ICCUI() { |  | ||||||
|     int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template <int func(int, const char *, const char *, int)> void WrapI_ICCI() { |  | ||||||
|     int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template <int func(const char *, int, int)> void WrapI_CII() { |  | ||||||
|     int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template <int func(int, const char *, int)> void WrapI_ICI() { |  | ||||||
|     int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, void *, void *, void *, void *, u32, int)> void WrapI_IVVVVUI(){ |  | ||||||
|     u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), Memory::GetPointer(PARAM(2)), Memory::GetPointer(PARAM(3)), Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) ); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(int, const char *, u32, void *, int, int, int)> void WrapI_ICUVIII(){ |  | ||||||
|     u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(void*, u32)> void WrapI_VU(){ |  | ||||||
|     u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(void*, void*, u32)> void WrapI_VVU(){ |  | ||||||
|     u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(void*, u32, void*, int)> void WrapI_VUVI(){ |  | ||||||
|     u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(void*, u32, u32, u32, u32, u32)> void WrapI_VUUUUU(){ |  | ||||||
|     u32 retval = func(NULL, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(u32, s64)> void WrapI_US64() { |  | ||||||
|     int retval = func(PARAM(0), PARAM64(1)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<int func(void*, void*, u32, u32, s64)> void WrapI_VVUUS64() { |  | ||||||
|     int retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); |  | ||||||
|     RETURN(retval); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| #include "core/mem_map.h" | #include "core/mem_map.h" | ||||||
| #include "core/hle/hle.h" | #include "core/hle/hle.h" | ||||||
| #include "core/hle/svc.h" | #include "core/hle/svc.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | @ -15,11 +16,13 @@ namespace HLE { | ||||||
| 
 | 
 | ||||||
| static std::vector<ModuleDef> g_module_db; | static std::vector<ModuleDef> g_module_db; | ||||||
| 
 | 
 | ||||||
|  | bool g_reschedule = false;  ///< If true, immediately reschedules the CPU to a new thread
 | ||||||
|  | 
 | ||||||
| const FunctionDef* GetSVCInfo(u32 opcode) { | const FunctionDef* GetSVCInfo(u32 opcode) { | ||||||
|     u32 func_num = opcode & 0xFFFFFF; // 8 bits
 |     u32 func_num = opcode & 0xFFFFFF; // 8 bits
 | ||||||
|     if (func_num > 0xFF) { |     if (func_num > 0xFF) { | ||||||
|         ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num);  |         ERROR_LOG(HLE,"unknown svc=0x%02X", func_num);  | ||||||
|         return NULL; |         return nullptr; | ||||||
|     } |     } | ||||||
|     return &g_module_db[0].func_table[func_num]; |     return &g_module_db[0].func_table[func_num]; | ||||||
| } | } | ||||||
|  | @ -33,19 +36,16 @@ void CallSVC(u32 opcode) { | ||||||
|     if (info->func) { |     if (info->func) { | ||||||
|         info->func(); |         info->func(); | ||||||
|     } else { |     } else { | ||||||
|         ERROR_LOG(HLE, "Unimplemented SVC function %s(..)", info->name.c_str()); |         ERROR_LOG(HLE, "unimplemented SVC function %s(..)", info->name.c_str()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void EatCycles(u32 cycles) { | void Reschedule(const char *reason) { | ||||||
|     // TODO: ImplementMe
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ReSchedule(const char *reason) { |  | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|     _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "ReSchedule: Invalid or too long reason."); |     _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason."); | ||||||
| #endif | #endif | ||||||
|     // TODO: ImplementMe
 |     Core::g_app_core->PrepareReschedule(); | ||||||
|  |     g_reschedule = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) { | void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) { | ||||||
|  |  | ||||||
|  | @ -9,14 +9,10 @@ | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| #define PARAM(n)        Core::g_app_core->GetReg(n) |  | ||||||
| #define PARAM64(n)      (Core::g_app_core->GetReg(n) | ((u64)Core::g_app_core->GetReg(n + 1) << 32)) |  | ||||||
| #define RETURN(n)       Core::g_app_core->SetReg(0, n) |  | ||||||
| 
 |  | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 |  | ||||||
| 
 |  | ||||||
| namespace HLE { | namespace HLE { | ||||||
| 
 | 
 | ||||||
|  | extern bool g_reschedule;   ///< If true, immediately reschedules the CPU to a new thread
 | ||||||
|  | 
 | ||||||
| typedef u32 Addr; | typedef u32 Addr; | ||||||
| typedef void (*Func)(); | typedef void (*Func)(); | ||||||
| 
 | 
 | ||||||
|  | @ -36,9 +32,7 @@ void RegisterModule(std::string name, int num_functions, const FunctionDef *func | ||||||
| 
 | 
 | ||||||
| void CallSVC(u32 opcode); | void CallSVC(u32 opcode); | ||||||
| 
 | 
 | ||||||
| void EatCycles(u32 cycles); | void Reschedule(const char *reason); | ||||||
| 
 |  | ||||||
| void ReSchedule(const char *reason); |  | ||||||
| 
 | 
 | ||||||
| void Init(); | void Init(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										159
									
								
								src/core/hle/kernel/event.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								src/core/hle/kernel/event.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,159 @@ | ||||||
|  | // Copyright 2014 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2
 | ||||||
|  | // Refer to the license.txt file included.  
 | ||||||
|  | 
 | ||||||
|  | #include <map> | ||||||
|  | #include <algorithm> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | #include "common/common.h" | ||||||
|  | 
 | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/kernel/event.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
|  | 
 | ||||||
|  | namespace Kernel { | ||||||
|  | 
 | ||||||
|  | class Event : public Object { | ||||||
|  | public: | ||||||
|  |     const char* GetTypeName() const { return "Event"; } | ||||||
|  |     const char* GetName() const { return name.c_str(); } | ||||||
|  | 
 | ||||||
|  |     static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; } | ||||||
|  |     Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; } | ||||||
|  | 
 | ||||||
|  |     ResetType intitial_reset_type;          ///< ResetType specified at Event initialization
 | ||||||
|  |     ResetType reset_type;                   ///< Current ResetType
 | ||||||
|  | 
 | ||||||
|  |     bool locked;                            ///< Event signal wait
 | ||||||
|  |     bool permanent_locked;                  ///< Hack - to set event permanent state (for easy passthrough)
 | ||||||
|  |     std::vector<Handle> waiting_threads;    ///< Threads that are waiting for the event
 | ||||||
|  |     std::string name;                       ///< Name of event (optional)
 | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Wait for kernel object to synchronize | ||||||
|  |      * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||||||
|  |      * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     Result WaitSynchronization(bool* wait) { | ||||||
|  |         *wait = locked; | ||||||
|  |         if (locked) { | ||||||
|  |             Handle thread = GetCurrentThreadHandle(); | ||||||
|  |             if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||||||
|  |                 waiting_threads.push_back(thread); | ||||||
|  |             } | ||||||
|  |             Kernel::WaitCurrentThread(WAITTYPE_EVENT); | ||||||
|  |         } | ||||||
|  |         if (reset_type != RESETTYPE_STICKY && !permanent_locked) { | ||||||
|  |             locked = true; | ||||||
|  |         } | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Hackish function to set an events permanent lock state, used to pass through synch blocks | ||||||
|  |  * @param handle Handle to event to change | ||||||
|  |  * @param permanent_locked Boolean permanent locked value to set event | ||||||
|  |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | Result SetPermanentLock(Handle handle, const bool permanent_locked) { | ||||||
|  |     Event* evt = g_object_pool.GetFast<Event>(handle); | ||||||
|  |     _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); | ||||||
|  | 
 | ||||||
|  |     evt->permanent_locked = permanent_locked; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Changes whether an event is locked or not | ||||||
|  |  * @param handle Handle to event to change | ||||||
|  |  * @param locked Boolean locked value to set event | ||||||
|  |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | Result SetEventLocked(const Handle handle, const bool locked) { | ||||||
|  |     Event* evt = g_object_pool.GetFast<Event>(handle); | ||||||
|  |     _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); | ||||||
|  | 
 | ||||||
|  |     if (!evt->permanent_locked) { | ||||||
|  |         evt->locked = locked; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Signals an event | ||||||
|  |  * @param handle Handle to event to signal | ||||||
|  |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | Result SignalEvent(const Handle handle) { | ||||||
|  |     Event* evt = g_object_pool.GetFast<Event>(handle); | ||||||
|  |     _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); | ||||||
|  | 
 | ||||||
|  |     // Resume threads waiting for event to signal
 | ||||||
|  |     bool event_caught = false; | ||||||
|  |     for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { | ||||||
|  |         ResumeThreadFromWait( evt->waiting_threads[i]); | ||||||
|  | 
 | ||||||
|  |         // If any thread is signalled awake by this event, assume the event was "caught" and reset 
 | ||||||
|  |         // the event. This will result in the next thread waiting on the event to block. Otherwise,
 | ||||||
|  |         // the event will not be reset, and the next thread to call WaitSynchronization on it will
 | ||||||
|  |         // not block. Not sure if this is correct behavior, but it seems to work.
 | ||||||
|  |         event_caught = true; | ||||||
|  |     } | ||||||
|  |     evt->waiting_threads.clear(); | ||||||
|  | 
 | ||||||
|  |     if (!evt->permanent_locked) { | ||||||
|  |         evt->locked = event_caught; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Clears an event | ||||||
|  |  * @param handle Handle to event to clear | ||||||
|  |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | Result ClearEvent(Handle handle) { | ||||||
|  |     Event* evt = g_object_pool.GetFast<Event>(handle); | ||||||
|  |     _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); | ||||||
|  | 
 | ||||||
|  |     if (!evt->permanent_locked) { | ||||||
|  |         evt->locked = true; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Creates an event | ||||||
|  |  * @param handle Reference to handle for the newly created mutex | ||||||
|  |  * @param reset_type ResetType describing how to create event | ||||||
|  |  * @param name Optional name of event | ||||||
|  |  * @return Newly created Event object | ||||||
|  |  */ | ||||||
|  | Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) { | ||||||
|  |     Event* evt = new Event; | ||||||
|  | 
 | ||||||
|  |     handle = Kernel::g_object_pool.Create(evt); | ||||||
|  | 
 | ||||||
|  |     evt->locked = true; | ||||||
|  |     evt->permanent_locked = false; | ||||||
|  |     evt->reset_type = evt->intitial_reset_type = reset_type; | ||||||
|  |     evt->name = name; | ||||||
|  | 
 | ||||||
|  |     return evt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Creates an event | ||||||
|  |  * @param reset_type ResetType describing how to create event | ||||||
|  |  * @param name Optional name of event | ||||||
|  |  * @return Handle to newly created Event object | ||||||
|  |  */ | ||||||
|  | Handle CreateEvent(const ResetType reset_type, const std::string& name) { | ||||||
|  |     Handle handle; | ||||||
|  |     Event* evt = CreateEvent(handle, reset_type, name); | ||||||
|  |     return handle; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
							
								
								
									
										52
									
								
								src/core/hle/kernel/event.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/core/hle/kernel/event.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | // Copyright 2014 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2
 | ||||||
|  | // Refer to the license.txt file included.  
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common/common_types.h" | ||||||
|  | 
 | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/svc.h" | ||||||
|  | 
 | ||||||
|  | namespace Kernel { | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Changes whether an event is locked or not | ||||||
|  |  * @param handle Handle to event to change | ||||||
|  |  * @param locked Boolean locked value to set event | ||||||
|  |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | Result SetEventLocked(const Handle handle, const bool locked); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Hackish function to set an events permanent lock state, used to pass through synch blocks | ||||||
|  |  * @param handle Handle to event to change | ||||||
|  |  * @param permanent_locked Boolean permanent locked value to set event | ||||||
|  |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | Result SetPermanentLock(Handle handle, const bool permanent_locked); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Signals an event | ||||||
|  |  * @param handle Handle to event to signal | ||||||
|  |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | Result SignalEvent(const Handle handle); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Clears an event | ||||||
|  |  * @param handle Handle to event to clear | ||||||
|  |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | Result ClearEvent(Handle handle); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Creates an event | ||||||
|  |  * @param reset_type ResetType describing how to create event | ||||||
|  |  * @param name Optional name of event | ||||||
|  |  * @return Handle to newly created Event object | ||||||
|  |  */ | ||||||
|  | Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown"); | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
|  | @ -2,8 +2,6 @@ | ||||||
| // Licensed under GPLv2
 | // Licensed under GPLv2
 | ||||||
| // Refer to the license.txt file included.  
 | // Refer to the license.txt file included.  
 | ||||||
| 
 | 
 | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <string.h> | #include <string.h> | ||||||
| 
 | 
 | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
|  | @ -14,6 +12,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
|  | Handle g_main_thread = 0; | ||||||
| ObjectPool g_object_pool; | ObjectPool g_object_pool; | ||||||
| 
 | 
 | ||||||
| ObjectPool::ObjectPool() { | ObjectPool::ObjectPool() { | ||||||
|  | @ -127,16 +126,20 @@ Object* ObjectPool::CreateByIDType(int type) { | ||||||
| 
 | 
 | ||||||
|     default: |     default: | ||||||
|         ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); |         ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); | ||||||
|         return NULL; |         return nullptr; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Initialize the kernel
 | ||||||
| void Init() { | void Init() { | ||||||
|     Kernel::ThreadingInit(); |     Kernel::ThreadingInit(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Shutdown the kernel
 | ||||||
| void Shutdown() { | void Shutdown() { | ||||||
|     Kernel::ThreadingShutdown(); |     Kernel::ThreadingShutdown(); | ||||||
|  | 
 | ||||||
|  |     g_object_pool.Clear(); // Free all kernel objects
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -150,7 +153,7 @@ bool LoadExec(u32 entry_point) { | ||||||
|     Core::g_app_core->SetPC(entry_point); |     Core::g_app_core->SetPC(entry_point); | ||||||
| 
 | 
 | ||||||
|     // 0x30 is the typical main thread priority I've seen used so far
 |     // 0x30 is the typical main thread priority I've seen used so far
 | ||||||
|     Handle thread = Kernel::SetupMainThread(0x30); |     g_main_thread = Kernel::SetupMainThread(0x30); | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -11,6 +11,11 @@ typedef s32 Result; | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
|  | enum KernelHandle { | ||||||
|  |     CurrentThread   = 0xFFFF8000, | ||||||
|  |     CurrentProcess  = 0xFFFF8001, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| enum class HandleType : u32 { | enum class HandleType : u32 { | ||||||
|     Unknown         = 0, |     Unknown         = 0, | ||||||
|     Port            = 1, |     Port            = 1, | ||||||
|  | @ -39,9 +44,26 @@ class Object : NonCopyable { | ||||||
| public: | public: | ||||||
|     virtual ~Object() {} |     virtual ~Object() {} | ||||||
|     Handle GetHandle() const { return handle; } |     Handle GetHandle() const { return handle; } | ||||||
|     virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; } |     virtual const char* GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; } | ||||||
|     virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; } |     virtual const char* GetName() const { return "[UNKNOWN KERNEL OBJECT]"; } | ||||||
|     virtual Kernel::HandleType GetHandleType() const = 0; |     virtual Kernel::HandleType GetHandleType() const = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Synchronize kernel object  | ||||||
|  |      * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||||||
|  |      * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     virtual Result SyncRequest(bool* wait) { | ||||||
|  |         ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Wait for kernel object to synchronize | ||||||
|  |      * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||||||
|  |      * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     virtual Result WaitSynchronization(bool* wait) = 0; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class ObjectPool : NonCopyable { | class ObjectPool : NonCopyable { | ||||||
|  | @ -143,6 +165,13 @@ private: | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| extern ObjectPool g_object_pool; | extern ObjectPool g_object_pool; | ||||||
|  | extern Handle g_main_thread; | ||||||
|  | 
 | ||||||
|  | /// Initialize the kernel
 | ||||||
|  | void Init(); | ||||||
|  | 
 | ||||||
|  | /// Shutdown the kernel
 | ||||||
|  | void Shutdown(); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Loads executable stored at specified address |  * Loads executable stored at specified address | ||||||
|  |  | ||||||
|  | @ -8,13 +8,15 @@ | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class Mutex : public Object { | class Mutex : public Object { | ||||||
| public: | public: | ||||||
|     const char* GetTypeName() { return "Mutex"; } |     const char* GetTypeName() const { return "Mutex"; } | ||||||
|  |     const char* GetName() const { return name.c_str(); } | ||||||
| 
 | 
 | ||||||
|     static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } |     static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } | ||||||
|     Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } |     Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } | ||||||
|  | @ -23,6 +25,34 @@ public: | ||||||
|     bool locked;                                ///< Current locked state
 |     bool locked;                                ///< Current locked state
 | ||||||
|     Handle lock_thread;                         ///< Handle to thread that currently has mutex
 |     Handle lock_thread;                         ///< Handle to thread that currently has mutex
 | ||||||
|     std::vector<Handle> waiting_threads;        ///< Threads that are waiting for the mutex
 |     std::vector<Handle> waiting_threads;        ///< Threads that are waiting for the mutex
 | ||||||
|  |     std::string name;                           ///< Name of mutex (optional)
 | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Synchronize kernel object  | ||||||
|  |      * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||||||
|  |      * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     Result SyncRequest(bool* wait) { | ||||||
|  |         // TODO(bunnei): ImplementMe
 | ||||||
|  |         locked = true; | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Wait for kernel object to synchronize | ||||||
|  |      * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||||||
|  |      * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     Result WaitSynchronization(bool* wait) { | ||||||
|  |         // TODO(bunnei): ImplementMe
 | ||||||
|  |         *wait = locked; | ||||||
|  | 
 | ||||||
|  |         if (locked) { | ||||||
|  |             Kernel::WaitCurrentThread(WAITTYPE_MUTEX); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | @ -70,10 +100,10 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread) { | ||||||
| bool ReleaseMutex(Mutex* mutex) { | bool ReleaseMutex(Mutex* mutex) { | ||||||
|     MutexEraseLock(mutex); |     MutexEraseLock(mutex); | ||||||
|     bool woke_threads = false; |     bool woke_threads = false; | ||||||
|     auto iter = mutex->waiting_threads.begin(); |  | ||||||
| 
 | 
 | ||||||
|     // Find the next waiting thread for the mutex...
 |     // Find the next waiting thread for the mutex...
 | ||||||
|     while (!woke_threads && !mutex->waiting_threads.empty()) { |     while (!woke_threads && !mutex->waiting_threads.empty()) { | ||||||
|  |         std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); | ||||||
|         woke_threads |= ReleaseMutexForThread(mutex, *iter); |         woke_threads |= ReleaseMutexForThread(mutex, *iter); | ||||||
|         mutex->waiting_threads.erase(iter); |         mutex->waiting_threads.erase(iter); | ||||||
|     } |     } | ||||||
|  | @ -91,6 +121,9 @@ bool ReleaseMutex(Mutex* mutex) { | ||||||
|  */ |  */ | ||||||
| Result ReleaseMutex(Handle handle) { | Result ReleaseMutex(Handle handle) { | ||||||
|     Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); |     Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); | ||||||
|  | 
 | ||||||
|  |     _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!"); | ||||||
|  | 
 | ||||||
|     if (!ReleaseMutex(mutex)) { |     if (!ReleaseMutex(mutex)) { | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|  | @ -101,12 +134,15 @@ Result ReleaseMutex(Handle handle) { | ||||||
|  * Creates a mutex |  * Creates a mutex | ||||||
|  * @param handle Reference to handle for the newly created mutex |  * @param handle Reference to handle for the newly created mutex | ||||||
|  * @param initial_locked Specifies if the mutex should be locked initially |  * @param initial_locked Specifies if the mutex should be locked initially | ||||||
|  |  * @param name Optional name of mutex | ||||||
|  |  * @return Pointer to new Mutex object | ||||||
|  */ |  */ | ||||||
| Mutex* CreateMutex(Handle& handle, bool initial_locked) { | Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { | ||||||
|     Mutex* mutex = new Mutex; |     Mutex* mutex = new Mutex; | ||||||
|     handle = Kernel::g_object_pool.Create(mutex); |     handle = Kernel::g_object_pool.Create(mutex); | ||||||
| 
 | 
 | ||||||
|     mutex->locked = mutex->initial_locked = initial_locked; |     mutex->locked = mutex->initial_locked = initial_locked; | ||||||
|  |     mutex->name = name; | ||||||
| 
 | 
 | ||||||
|     // Acquire mutex with current thread if initialized as locked...
 |     // Acquire mutex with current thread if initialized as locked...
 | ||||||
|     if (mutex->locked) { |     if (mutex->locked) { | ||||||
|  | @ -122,10 +158,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked) { | ||||||
| /**
 | /**
 | ||||||
|  * Creates a mutex |  * Creates a mutex | ||||||
|  * @param initial_locked Specifies if the mutex should be locked initially |  * @param initial_locked Specifies if the mutex should be locked initially | ||||||
|  |  * @param name Optional name of mutex | ||||||
|  |  * @return Handle to newly created object | ||||||
|  */ |  */ | ||||||
| Handle CreateMutex(bool initial_locked) { | Handle CreateMutex(bool initial_locked, const std::string& name) { | ||||||
|     Handle handle; |     Handle handle; | ||||||
|     Mutex* mutex = CreateMutex(handle, initial_locked); |     Mutex* mutex = CreateMutex(handle, initial_locked, name); | ||||||
|     return handle; |     return handle; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,14 +13,16 @@ namespace Kernel { | ||||||
| /**
 | /**
 | ||||||
|  * Releases a mutex |  * Releases a mutex | ||||||
|  * @param handle Handle to mutex to release |  * @param handle Handle to mutex to release | ||||||
|  |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  */ |  */ | ||||||
| Result ReleaseMutex(Handle handle); | Result ReleaseMutex(Handle handle); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Creates a mutex |  * Creates a mutex | ||||||
|  * @param handle Reference to handle for the newly created mutex |  | ||||||
|  * @param initial_locked Specifies if the mutex should be locked initially |  * @param initial_locked Specifies if the mutex should be locked initially | ||||||
|  |  * @param name Optional name of mutex | ||||||
|  |  * @return Handle to newly created object | ||||||
|  */ |  */ | ||||||
| Handle CreateMutex(bool initial_locked); | Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| #include <list> | #include <list> | ||||||
|  | #include <algorithm> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <map> | #include <map> | ||||||
| #include <string> | #include <string> | ||||||
|  | @ -24,8 +25,8 @@ namespace Kernel { | ||||||
| class Thread : public Kernel::Object { | class Thread : public Kernel::Object { | ||||||
| public: | public: | ||||||
| 
 | 
 | ||||||
|     const char* GetName() { return name; } |     const char* GetName() const { return name; } | ||||||
|     const char* GetTypeName() { return "Thread"; } |     const char* GetTypeName() const { return "Thread"; } | ||||||
| 
 | 
 | ||||||
|     static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } |     static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } | ||||||
|     Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } |     Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } | ||||||
|  | @ -36,6 +37,23 @@ public: | ||||||
|     inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } |     inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } | ||||||
|     inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } |     inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Wait for kernel object to synchronize | ||||||
|  |      * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||||||
|  |      * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     Result WaitSynchronization(bool* wait) { | ||||||
|  |         if (status != THREADSTATUS_DORMANT) { | ||||||
|  |             Handle thread = GetCurrentThreadHandle(); | ||||||
|  |             if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||||||
|  |                 waiting_threads.push_back(thread); | ||||||
|  |             } | ||||||
|  |             WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); | ||||||
|  |             *wait = true; | ||||||
|  |         } | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     ThreadContext context; |     ThreadContext context; | ||||||
| 
 | 
 | ||||||
|     u32 status; |     u32 status; | ||||||
|  | @ -49,6 +67,9 @@ public: | ||||||
|     s32 processor_id; |     s32 processor_id; | ||||||
| 
 | 
 | ||||||
|     WaitType wait_type; |     WaitType wait_type; | ||||||
|  |     Handle wait_handle; | ||||||
|  | 
 | ||||||
|  |     std::vector<Handle> waiting_threads; | ||||||
| 
 | 
 | ||||||
|     char name[Kernel::MAX_NAME_LENGTH + 1]; |     char name[Kernel::MAX_NAME_LENGTH + 1]; | ||||||
| }; | }; | ||||||
|  | @ -62,7 +83,6 @@ Common::ThreadQueueList<Handle> g_thread_ready_queue; | ||||||
| Handle g_current_thread_handle; | Handle g_current_thread_handle; | ||||||
| Thread* g_current_thread; | Thread* g_current_thread; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /// Gets the current thread
 | /// Gets the current thread
 | ||||||
| inline Thread* GetCurrentThread() { | inline Thread* GetCurrentThread() { | ||||||
|     return g_current_thread; |     return g_current_thread; | ||||||
|  | @ -94,15 +114,15 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { | ||||||
|     memset(&t->context, 0, sizeof(ThreadContext)); |     memset(&t->context, 0, sizeof(ThreadContext)); | ||||||
| 
 | 
 | ||||||
|     t->context.cpu_registers[0] = arg; |     t->context.cpu_registers[0] = arg; | ||||||
|     t->context.pc = t->entry_point; |     t->context.pc = t->context.reg_15 = t->entry_point; | ||||||
|     t->context.sp = t->stack_top; |     t->context.sp = t->stack_top; | ||||||
|     t->context.cpsr = 0x1F; // Usermode
 |     t->context.cpsr = 0x1F; // Usermode
 | ||||||
|      |      | ||||||
|     if (t->current_priority < lowest_priority) { |     if (t->current_priority < lowest_priority) { | ||||||
|         t->current_priority = t->initial_priority; |         t->current_priority = t->initial_priority; | ||||||
|     } |     } | ||||||
|          |  | ||||||
|     t->wait_type = WAITTYPE_NONE; |     t->wait_type = WAITTYPE_NONE; | ||||||
|  |     t->wait_handle = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Change a thread to "ready" state
 | /// Change a thread to "ready" state
 | ||||||
|  | @ -122,6 +142,37 @@ void ChangeReadyState(Thread* t, bool ready) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Verify that a thread has not been released from waiting
 | ||||||
|  | inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { | ||||||
|  |     Thread* thread = g_object_pool.GetFast<Thread>(handle); | ||||||
|  |     _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||||||
|  | 
 | ||||||
|  |     if (type != thread->wait_type || wait_handle != thread->wait_handle)  | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Stops the current thread
 | ||||||
|  | void StopThread(Handle handle, const char* reason) { | ||||||
|  |     Thread* thread = g_object_pool.GetFast<Thread>(handle); | ||||||
|  |     _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||||||
|  |      | ||||||
|  |     ChangeReadyState(thread, false); | ||||||
|  |     thread->status = THREADSTATUS_DORMANT; | ||||||
|  |     for (size_t i = 0; i < thread->waiting_threads.size(); ++i) { | ||||||
|  |         const Handle waiting_thread = thread->waiting_threads[i]; | ||||||
|  |         if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { | ||||||
|  |             ResumeThreadFromWait(waiting_thread); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     thread->waiting_threads.clear(); | ||||||
|  | 
 | ||||||
|  |     // Stopped threads are never waiting.
 | ||||||
|  |     thread->wait_type = WAITTYPE_NONE; | ||||||
|  |     thread->wait_handle = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Changes a threads state
 | /// Changes a threads state
 | ||||||
| void ChangeThreadState(Thread* t, ThreadStatus new_status) { | void ChangeThreadState(Thread* t, ThreadStatus new_status) { | ||||||
|     if (!t || t->status == new_status) { |     if (!t || t->status == new_status) { | ||||||
|  | @ -132,7 +183,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) { | ||||||
|      |      | ||||||
|     if (new_status == THREADSTATUS_WAIT) { |     if (new_status == THREADSTATUS_WAIT) { | ||||||
|         if (t->wait_type == WAITTYPE_NONE) { |         if (t->wait_type == WAITTYPE_NONE) { | ||||||
|             printf("ERROR: Waittype none not allowed here\n"); |             ERROR_LOG(KERNEL, "Waittype none not allowed"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -166,7 +217,7 @@ void SwitchContext(Thread* t) { | ||||||
|         t->wait_type = WAITTYPE_NONE; |         t->wait_type = WAITTYPE_NONE; | ||||||
|         LoadContext(t->context); |         LoadContext(t->context); | ||||||
|     } else { |     } else { | ||||||
|         SetCurrentThread(NULL); |         SetCurrentThread(nullptr); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -181,26 +232,43 @@ Thread* NextThread() { | ||||||
|         next = g_thread_ready_queue.pop_first(); |         next = g_thread_ready_queue.pop_first(); | ||||||
|     } |     } | ||||||
|     if (next == 0) { |     if (next == 0) { | ||||||
|         return NULL; |         return nullptr; | ||||||
|     } |     } | ||||||
|     return Kernel::g_object_pool.GetFast<Thread>(next); |     return Kernel::g_object_pool.GetFast<Thread>(next); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Puts the current thread in the wait state for the given type
 | /// Puts the current thread in the wait state for the given type
 | ||||||
| void WaitCurrentThread(WaitType wait_type) { | void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { | ||||||
|     Thread* t = GetCurrentThread(); |     Thread* thread = GetCurrentThread(); | ||||||
|     t->wait_type = wait_type; |     thread->wait_type = wait_type; | ||||||
|     ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); |     thread->wait_handle = wait_handle; | ||||||
|  |     ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Resumes a thread from waiting by marking it as "ready"
 | /// Resumes a thread from waiting by marking it as "ready"
 | ||||||
| void ResumeThreadFromWait(Handle handle) { | void ResumeThreadFromWait(Handle handle) { | ||||||
|     u32 error; |     u32 error; | ||||||
|     Thread* t = Kernel::g_object_pool.Get<Thread>(handle, error); |     Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error); | ||||||
|     if (t) { |     if (thread) { | ||||||
|         t->status &= ~THREADSTATUS_WAIT; |         thread->status &= ~THREADSTATUS_WAIT; | ||||||
|         if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |         if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | ||||||
|             ChangeReadyState(t, true); |             ChangeReadyState(thread, true); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Prints the thread queue for debugging purposes
 | ||||||
|  | void DebugThreadQueue() { | ||||||
|  |     Thread* thread = GetCurrentThread(); | ||||||
|  |     if (!thread) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); | ||||||
|  |     for (u32 i = 0; i < g_thread_queue.size(); i++) { | ||||||
|  |         Handle handle = g_thread_queue[i]; | ||||||
|  |         s32 priority = g_thread_ready_queue.contains(handle); | ||||||
|  |         if (priority != -1) { | ||||||
|  |             INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -212,32 +280,34 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio | ||||||
|     _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),  |     _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),  | ||||||
|         "CreateThread priority=%d, outside of allowable range!", priority) |         "CreateThread priority=%d, outside of allowable range!", priority) | ||||||
| 
 | 
 | ||||||
|     Thread* t = new Thread; |     Thread* thread = new Thread; | ||||||
| 
 | 
 | ||||||
|     handle = Kernel::g_object_pool.Create(t); |     handle = Kernel::g_object_pool.Create(thread); | ||||||
| 
 | 
 | ||||||
|     g_thread_queue.push_back(handle); |     g_thread_queue.push_back(handle); | ||||||
|     g_thread_ready_queue.prepare(priority); |     g_thread_ready_queue.prepare(priority); | ||||||
| 
 | 
 | ||||||
|     t->status = THREADSTATUS_DORMANT; |     thread->status = THREADSTATUS_DORMANT; | ||||||
|     t->entry_point = entry_point; |     thread->entry_point = entry_point; | ||||||
|     t->stack_top = stack_top; |     thread->stack_top = stack_top; | ||||||
|     t->stack_size = stack_size; |     thread->stack_size = stack_size; | ||||||
|     t->initial_priority = t->current_priority = priority; |     thread->initial_priority = thread->current_priority = priority; | ||||||
|     t->processor_id = processor_id; |     thread->processor_id = processor_id; | ||||||
|     t->wait_type = WAITTYPE_NONE; |     thread->wait_type = WAITTYPE_NONE; | ||||||
|  |     thread->wait_handle = 0; | ||||||
| 
 | 
 | ||||||
|     strncpy(t->name, name, Kernel::MAX_NAME_LENGTH); |     strncpy(thread->name, name, Kernel::MAX_NAME_LENGTH); | ||||||
|     t->name[Kernel::MAX_NAME_LENGTH] = '\0'; |     thread->name[Kernel::MAX_NAME_LENGTH] = '\0'; | ||||||
| 
 | 
 | ||||||
|     return t; |     return thread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Creates a new thread - wrapper for external user
 | /// Creates a new thread - wrapper for external user
 | ||||||
| Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, | Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, | ||||||
|     u32 stack_top, int stack_size) { |     u32 stack_top, int stack_size) { | ||||||
|     if (name == NULL) { | 
 | ||||||
|         ERROR_LOG(KERNEL, "CreateThread(): NULL name"); |     if (name == nullptr) { | ||||||
|  |         ERROR_LOG(KERNEL, "CreateThread(): nullptr name"); | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|     if ((u32)stack_size < 0x200) { |     if ((u32)stack_size < 0x200) { | ||||||
|  | @ -258,31 +328,67 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|     Handle handle; |     Handle handle; | ||||||
|     Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,  |     Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,  | ||||||
|         stack_size); |         stack_size); | ||||||
| 
 | 
 | ||||||
|     ResetThread(t, arg, 0); |     ResetThread(thread, arg, 0); | ||||||
| 
 |     CallThread(thread); | ||||||
|     HLE::EatCycles(32000); |  | ||||||
| 
 |  | ||||||
|     // This won't schedule to the new thread, but it may to one woken from eating cycles.
 |  | ||||||
|     // Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
 |  | ||||||
|     HLE::ReSchedule("thread created"); |  | ||||||
| 
 |  | ||||||
|     CallThread(t); |  | ||||||
| 
 | 
 | ||||||
|     return handle; |     return handle; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Get the priority of the thread specified by handle
 | ||||||
|  | u32 GetThreadPriority(const Handle handle) { | ||||||
|  |     Thread* thread = g_object_pool.GetFast<Thread>(handle); | ||||||
|  |     _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||||||
|  |     return thread->current_priority; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Set the priority of the thread specified by handle
 | ||||||
|  | Result SetThreadPriority(Handle handle, s32 priority) { | ||||||
|  |     Thread* thread = nullptr; | ||||||
|  |     if (!handle) { | ||||||
|  |         thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
 | ||||||
|  |     } else { | ||||||
|  |         thread = g_object_pool.GetFast<Thread>(handle); | ||||||
|  |     } | ||||||
|  |     _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||||||
|  | 
 | ||||||
|  |     // If priority is invalid, clamp to valid range
 | ||||||
|  |     if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | ||||||
|  |         s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | ||||||
|  |         WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority); | ||||||
|  |         // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
 | ||||||
|  |         // validity of this
 | ||||||
|  |         priority = new_priority; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Change thread priority
 | ||||||
|  |     s32 old = thread->current_priority; | ||||||
|  |     g_thread_ready_queue.remove(old, handle); | ||||||
|  |     thread->current_priority = priority; | ||||||
|  |     g_thread_ready_queue.prepare(thread->current_priority); | ||||||
|  | 
 | ||||||
|  |     // Change thread status to "ready" and push to ready queue
 | ||||||
|  |     if (thread->IsRunning()) { | ||||||
|  |         thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; | ||||||
|  |     } | ||||||
|  |     if (thread->IsReady()) { | ||||||
|  |         g_thread_ready_queue.push_back(thread->current_priority, handle); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Sets up the primary application thread
 | /// Sets up the primary application thread
 | ||||||
| Handle SetupMainThread(s32 priority, int stack_size) { | Handle SetupMainThread(s32 priority, int stack_size) { | ||||||
|     Handle handle; |     Handle handle; | ||||||
|      |      | ||||||
|     // Initialize new "main" thread
 |     // Initialize new "main" thread
 | ||||||
|     Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,  |     Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,  | ||||||
|         THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); |         THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); | ||||||
|      |      | ||||||
|     ResetThread(t, 0, 0); |     ResetThread(thread, 0, 0); | ||||||
|      |      | ||||||
|     // If running another thread already, set it to "ready" state
 |     // If running another thread already, set it to "ready" state
 | ||||||
|     Thread* cur = GetCurrentThread(); |     Thread* cur = GetCurrentThread(); | ||||||
|  | @ -291,24 +397,31 @@ Handle SetupMainThread(s32 priority, int stack_size) { | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     // Run new "main" thread
 |     // Run new "main" thread
 | ||||||
|     SetCurrentThread(t); |     SetCurrentThread(thread); | ||||||
|     t->status = THREADSTATUS_RUNNING; |     thread->status = THREADSTATUS_RUNNING; | ||||||
|     LoadContext(t->context); |     LoadContext(thread->context); | ||||||
| 
 | 
 | ||||||
|     return handle; |     return handle; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /// Reschedules to the next available thread (call after current thread is suspended)
 | /// Reschedules to the next available thread (call after current thread is suspended)
 | ||||||
| void Reschedule() { | void Reschedule() { | ||||||
|     Thread* prev = GetCurrentThread(); |     Thread* prev = GetCurrentThread(); | ||||||
|     Thread* next = NextThread(); |     Thread* next = NextThread(); | ||||||
|  |     HLE::g_reschedule = false; | ||||||
|     if (next > 0) { |     if (next > 0) { | ||||||
|  |         INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); | ||||||
|  |          | ||||||
|         SwitchContext(next); |         SwitchContext(next); | ||||||
| 
 | 
 | ||||||
|         // Hack - automatically change previous thread (which would have been in "wait" state) to
 |         // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep
 | ||||||
|         // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to
 |         // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again.
 | ||||||
|         // actually wait for whatever event it is supposed to be waiting on.
 |         // This results in the current thread yielding on a VBLANK once, and then it will be 
 | ||||||
|         ChangeReadyState(prev, true); |         // immediately placed back in the queue for execution.
 | ||||||
|  |         if (prev->wait_type == WAITTYPE_VBLANK) { | ||||||
|  |             ResumeThreadFromWait(prev->GetHandle()); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -34,7 +34,7 @@ enum WaitType { | ||||||
|     WAITTYPE_NONE, |     WAITTYPE_NONE, | ||||||
|     WAITTYPE_SLEEP, |     WAITTYPE_SLEEP, | ||||||
|     WAITTYPE_SEMA, |     WAITTYPE_SEMA, | ||||||
|     WAITTYPE_EVENTFLAG, |     WAITTYPE_EVENT, | ||||||
|     WAITTYPE_THREADEND, |     WAITTYPE_THREADEND, | ||||||
|     WAITTYPE_VBLANK, |     WAITTYPE_VBLANK, | ||||||
|     WAITTYPE_MUTEX, |     WAITTYPE_MUTEX, | ||||||
|  | @ -53,8 +53,8 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); | ||||||
| /// Reschedules to the next available thread (call after current thread is suspended)
 | /// Reschedules to the next available thread (call after current thread is suspended)
 | ||||||
| void Reschedule(); | void Reschedule(); | ||||||
| 
 | 
 | ||||||
| /// Puts the current thread in the wait state for the given type
 | /// Stops the current thread
 | ||||||
| void WaitCurrentThread(WaitType wait_type); | void StopThread(Handle thread, const char* reason); | ||||||
| 
 | 
 | ||||||
| /// Resumes a thread from waiting by marking it as "ready"
 | /// Resumes a thread from waiting by marking it as "ready"
 | ||||||
| void ResumeThreadFromWait(Handle handle); | void ResumeThreadFromWait(Handle handle); | ||||||
|  | @ -62,9 +62,18 @@ void ResumeThreadFromWait(Handle handle); | ||||||
| /// Gets the current thread handle
 | /// Gets the current thread handle
 | ||||||
| Handle GetCurrentThreadHandle(); | Handle GetCurrentThreadHandle(); | ||||||
| 
 | 
 | ||||||
|  | /// Puts the current thread in the wait state for the given type
 | ||||||
|  | void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle()); | ||||||
|  | 
 | ||||||
| /// Put current thread in a wait state - on WaitSynchronization
 | /// Put current thread in a wait state - on WaitSynchronization
 | ||||||
| void WaitThread_Synchronization(); | void WaitThread_Synchronization(); | ||||||
| 
 | 
 | ||||||
|  | /// Get the priority of the thread specified by handle
 | ||||||
|  | u32 GetThreadPriority(const Handle handle); | ||||||
|  | 
 | ||||||
|  | /// Set the priority of the thread specified by handle
 | ||||||
|  | Result SetThreadPriority(Handle handle, s32 priority); | ||||||
|  | 
 | ||||||
| /// Initialize threading
 | /// Initialize threading
 | ||||||
| void ThreadingInit(); | void ThreadingInit(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hle/hle.h" | #include "core/hle/hle.h" | ||||||
|  | #include "core/hle/kernel/event.h" | ||||||
| #include "core/hle/kernel/mutex.h" | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/service/apt.h" | #include "core/hle/service/apt.h" | ||||||
| 
 | 
 | ||||||
|  | @ -15,96 +16,120 @@ | ||||||
| namespace APT_U { | namespace APT_U { | ||||||
| 
 | 
 | ||||||
| void Initialize(Service::Interface* self) { | void Initialize(Service::Interface* self) { | ||||||
|     NOTICE_LOG(OSHLE, "APT_U::Sync - Initialize"); |     u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|  |     DEBUG_LOG(KERNEL, "called"); | ||||||
|  |      | ||||||
|  |     cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu");  // APT menu event handle
 | ||||||
|  |     cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle
 | ||||||
|  | 
 | ||||||
|  |     Kernel::SetEventLocked(cmd_buff[3], true); | ||||||
|  |     Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event
 | ||||||
|  | 
 | ||||||
|  |     cmd_buff[1] = 0; // No error
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetLockHandle(Service::Interface* self) { | void GetLockHandle(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Service::GetCommandBuffer(); |     u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|     u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
 |     u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
 | ||||||
|     cmd_buff[1] = 0; // No error
 |     cmd_buff[1] = 0; // No error
 | ||||||
|     cmd_buff[5] = Kernel::CreateMutex(false); |     cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock"); | ||||||
|     DEBUG_LOG(KERNEL, "APT_U::GetLockHandle called : created handle 0x%08X", cmd_buff[5]); |     DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Enable(Service::Interface* self) { | ||||||
|  |     u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|  |     u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
 | ||||||
|  |     cmd_buff[1] = 0; // No error
 | ||||||
|  |     ERROR_LOG(KERNEL, "(UNIMPEMENTED) called unk=0x%08X", unk); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void InquireNotification(Service::Interface* self) { | ||||||
|  |     u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|  |     u32 app_id = cmd_buff[2]; | ||||||
|  |     cmd_buff[1] = 0; // No error
 | ||||||
|  |     cmd_buff[3] = 0; // Signal type
 | ||||||
|  |     ERROR_LOG(KERNEL, "(UNIMPEMENTED) called app_id=0x%08X", app_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const Interface::FunctionInfo FunctionTable[] = { | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x00010040, GetLockHandle,         "GetLockHandle"}, |     {0x00010040, GetLockHandle,         "GetLockHandle"}, | ||||||
|     {0x00020080, Initialize,            "Initialize"}, |     {0x00020080, Initialize,            "Initialize"}, | ||||||
|     {0x00030040, NULL,          "Enable"}, |     {0x00030040, Enable,                "Enable"}, | ||||||
|     {0x00040040, NULL,          "Finalize"}, |     {0x00040040, nullptr,               "Finalize"}, | ||||||
|     {0x00050040, NULL,          "GetAppletManInfo"}, |     {0x00050040, nullptr,               "GetAppletManInfo"}, | ||||||
|     {0x00060040, NULL,          "GetAppletInfo"}, |     {0x00060040, nullptr,               "GetAppletInfo"}, | ||||||
|     {0x00070000, NULL,          "GetLastSignaledAppletId"}, |     {0x00070000, nullptr,               "GetLastSignaledAppletId"}, | ||||||
|     {0x00080000, NULL,          "CountRegisteredApplet"}, |     {0x00080000, nullptr,               "CountRegisteredApplet"}, | ||||||
|     {0x00090040, NULL,          "IsRegistered"}, |     {0x00090040, nullptr,               "IsRegistered"}, | ||||||
|     {0x000A0040, NULL,          "GetAttribute"}, |     {0x000A0040, nullptr,               "GetAttribute"}, | ||||||
|     {0x000B0040, NULL,          "InquireNotification"}, |     {0x000B0040, InquireNotification,   "InquireNotification"}, | ||||||
|     {0x000C0104, NULL,          "SendParameter"}, |     {0x000C0104, nullptr,                "SendParameter"}, | ||||||
|     {0x000D0080, NULL,          "ReceiveParameter"}, |     {0x000D0080, nullptr,                "ReceiveParameter"}, | ||||||
|     {0x000E0080, NULL,          "GlanceParameter"}, |     {0x000E0080, nullptr,                "GlanceParameter"}, | ||||||
|     {0x000F0100, NULL,          "CancelParameter"}, |     {0x000F0100, nullptr,                "CancelParameter"}, | ||||||
|     {0x001000C2, NULL,          "DebugFunc"}, |     {0x001000C2, nullptr,                "DebugFunc"}, | ||||||
|     {0x001100C0, NULL,          "MapProgramIdForDebug"}, |     {0x001100C0, nullptr,                "MapProgramIdForDebug"}, | ||||||
|     {0x00120040, NULL,          "SetHomeMenuAppletIdForDebug"}, |     {0x00120040, nullptr,                "SetHomeMenuAppletIdForDebug"}, | ||||||
|     {0x00130000, NULL,          "GetPreparationState"}, |     {0x00130000, nullptr,                "GetPreparationState"}, | ||||||
|     {0x00140040, NULL,          "SetPreparationState"}, |     {0x00140040, nullptr,                "SetPreparationState"}, | ||||||
|     {0x00150140, NULL,          "PrepareToStartApplication"}, |     {0x00150140, nullptr,                "PrepareToStartApplication"}, | ||||||
|     {0x00160040, NULL,          "PreloadLibraryApplet"}, |     {0x00160040, nullptr,                "PreloadLibraryApplet"}, | ||||||
|     {0x00170040, NULL,          "FinishPreloadingLibraryApplet"}, |     {0x00170040, nullptr,                "FinishPreloadingLibraryApplet"}, | ||||||
|     {0x00180040, NULL,          "PrepareToStartLibraryApplet"}, |     {0x00180040, nullptr,                "PrepareToStartLibraryApplet"}, | ||||||
|     {0x00190040, NULL,          "PrepareToStartSystemApplet"}, |     {0x00190040, nullptr,                "PrepareToStartSystemApplet"}, | ||||||
|     {0x001A0000, NULL,          "PrepareToStartNewestHomeMenu"}, |     {0x001A0000, nullptr,                "PrepareToStartNewestHomeMenu"}, | ||||||
|     {0x001B00C4, NULL,          "StartApplication"}, |     {0x001B00C4, nullptr,                "StartApplication"}, | ||||||
|     {0x001C0000, NULL,          "WakeupApplication"}, |     {0x001C0000, nullptr,                "WakeupApplication"}, | ||||||
|     {0x001D0000, NULL,          "CancelApplication"}, |     {0x001D0000, nullptr,                "CancelApplication"}, | ||||||
|     {0x001E0084, NULL,          "StartLibraryApplet"}, |     {0x001E0084, nullptr,                "StartLibraryApplet"}, | ||||||
|     {0x001F0084, NULL,          "StartSystemApplet"}, |     {0x001F0084, nullptr,                "StartSystemApplet"}, | ||||||
|     {0x00200044, NULL,          "StartNewestHomeMenu"}, |     {0x00200044, nullptr,                "StartNewestHomeMenu"}, | ||||||
|     {0x00210000, NULL,          "OrderToCloseApplication"}, |     {0x00210000, nullptr,                "OrderToCloseApplication"}, | ||||||
|     {0x00220040, NULL,          "PrepareToCloseApplication"}, |     {0x00220040, nullptr,                "PrepareToCloseApplication"}, | ||||||
|     {0x00230040, NULL,          "PrepareToJumpToApplication"}, |     {0x00230040, nullptr,                "PrepareToJumpToApplication"}, | ||||||
|     {0x00240044, NULL,          "JumpToApplication"}, |     {0x00240044, nullptr,                "JumpToApplication"}, | ||||||
|     {0x002500C0, NULL,          "PrepareToCloseLibraryApplet"}, |     {0x002500C0, nullptr,                "PrepareToCloseLibraryApplet"}, | ||||||
|     {0x00260000, NULL,          "PrepareToCloseSystemApplet"}, |     {0x00260000, nullptr,                "PrepareToCloseSystemApplet"}, | ||||||
|     {0x00270044, NULL,          "CloseApplication"}, |     {0x00270044, nullptr,                "CloseApplication"}, | ||||||
|     {0x00280044, NULL,          "CloseLibraryApplet"}, |     {0x00280044, nullptr,                "CloseLibraryApplet"}, | ||||||
|     {0x00290044, NULL,          "CloseSystemApplet"}, |     {0x00290044, nullptr,                "CloseSystemApplet"}, | ||||||
|     {0x002A0000, NULL,          "OrderToCloseSystemApplet"}, |     {0x002A0000, nullptr,                "OrderToCloseSystemApplet"}, | ||||||
|     {0x002B0000, NULL,          "PrepareToJumpToHomeMenu"}, |     {0x002B0000, nullptr,                "PrepareToJumpToHomeMenu"}, | ||||||
|     {0x002C0044, NULL,          "JumpToHomeMenu"}, |     {0x002C0044, nullptr,                "JumpToHomeMenu"}, | ||||||
|     {0x002D0000, NULL,          "PrepareToLeaveHomeMenu"}, |     {0x002D0000, nullptr,                "PrepareToLeaveHomeMenu"}, | ||||||
|     {0x002E0044, NULL,          "LeaveHomeMenu"}, |     {0x002E0044, nullptr,                "LeaveHomeMenu"}, | ||||||
|     {0x002F0040, NULL,          "PrepareToLeaveResidentApplet"}, |     {0x002F0040, nullptr,                "PrepareToLeaveResidentApplet"}, | ||||||
|     {0x00300044, NULL,          "LeaveResidentApplet"}, |     {0x00300044, nullptr,                "LeaveResidentApplet"}, | ||||||
|     {0x00310100, NULL,          "PrepareToDoApplicationJump"}, |     {0x00310100, nullptr,                "PrepareToDoApplicationJump"}, | ||||||
|     {0x00320084, NULL,          "DoApplicationJump"}, |     {0x00320084, nullptr,                "DoApplicationJump"}, | ||||||
|     {0x00330000, NULL,          "GetProgramIdOnApplicationJump"}, |     {0x00330000, nullptr,                "GetProgramIdOnApplicationJump"}, | ||||||
|     {0x00340084, NULL,          "SendDeliverArg"}, |     {0x00340084, nullptr,                "SendDeliverArg"}, | ||||||
|     {0x00350080, NULL,          "ReceiveDeliverArg"}, |     {0x00350080, nullptr,                "ReceiveDeliverArg"}, | ||||||
|     {0x00360040, NULL,          "LoadSysMenuArg"}, |     {0x00360040, nullptr,                "LoadSysMenuArg"}, | ||||||
|     {0x00370042, NULL,          "StoreSysMenuArg"}, |     {0x00370042, nullptr,                "StoreSysMenuArg"}, | ||||||
|     {0x00380040, NULL,          "PreloadResidentApplet"}, |     {0x00380040, nullptr,                "PreloadResidentApplet"}, | ||||||
|     {0x00390040, NULL,          "PrepareToStartResidentApplet"}, |     {0x00390040, nullptr,                "PrepareToStartResidentApplet"}, | ||||||
|     {0x003A0044, NULL,          "StartResidentApplet"}, |     {0x003A0044, nullptr,                "StartResidentApplet"}, | ||||||
|     {0x003B0040, NULL,          "CancelLibraryApplet"}, |     {0x003B0040, nullptr,                "CancelLibraryApplet"}, | ||||||
|     {0x003C0042, NULL,          "SendDspSleep"}, |     {0x003C0042, nullptr,                "SendDspSleep"}, | ||||||
|     {0x003D0042, NULL,          "SendDspWakeUp"}, |     {0x003D0042, nullptr,                "SendDspWakeUp"}, | ||||||
|     {0x003E0080, NULL,          "ReplySleepQuery"}, |     {0x003E0080, nullptr,                "ReplySleepQuery"}, | ||||||
|     {0x003F0040, NULL,          "ReplySleepNotificationComplete"}, |     {0x003F0040, nullptr,                "ReplySleepNotificationComplete"}, | ||||||
|     {0x00400042, NULL,          "SendCaptureBufferInfo"}, |     {0x00400042, nullptr,                "SendCaptureBufferInfo"}, | ||||||
|     {0x00410040, NULL,          "ReceiveCaptureBufferInfo"}, |     {0x00410040, nullptr,                "ReceiveCaptureBufferInfo"}, | ||||||
|     {0x00420080, NULL,          "SleepSystem"}, |     {0x00420080, nullptr,                "SleepSystem"}, | ||||||
|     {0x00430040, NULL,          "NotifyToWait"}, |     {0x00430040, nullptr,                "NotifyToWait"}, | ||||||
|     {0x00440000, NULL,          "GetSharedFont"}, |     {0x00440000, nullptr,                "GetSharedFont"}, | ||||||
|     {0x00450040, NULL,          "GetWirelessRebootInfo"}, |     {0x00450040, nullptr,                "GetWirelessRebootInfo"}, | ||||||
|     {0x00460104, NULL,          "Wrap"}, |     {0x00460104, nullptr,                "Wrap"}, | ||||||
|     {0x00470104, NULL,          "Unwrap"}, |     {0x00470104, nullptr,                "Unwrap"}, | ||||||
|     {0x00480100, NULL,          "GetProgramInfo"}, |     {0x00480100, nullptr,                "GetProgramInfo"}, | ||||||
|     {0x00490180, NULL,          "Reboot"}, |     {0x00490180, nullptr,                "Reboot"}, | ||||||
|     {0x004A0040, NULL,          "GetCaptureInfo"}, |     {0x004A0040, nullptr,                "GetCaptureInfo"}, | ||||||
|     {0x004B00C2, NULL,          "AppletUtility"}, |     {0x004B00C2, nullptr,                "AppletUtility"}, | ||||||
|     {0x004C0000, NULL,          "SetFatalErrDispMode"}, |     {0x004C0000, nullptr,                "SetFatalErrDispMode"}, | ||||||
|     {0x004D0080, NULL,          "GetAppletProgramInfo"}, |     {0x004D0080, nullptr,                "GetAppletProgramInfo"}, | ||||||
|     {0x004E0000, NULL,          "HardwareResetAsync"}, |     {0x004E0000, nullptr,                "HardwareResetAsync"}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "core/mem_map.h" | #include "core/mem_map.h" | ||||||
| #include "core/hle/hle.h" | #include "core/hle/hle.h" | ||||||
|  | #include "core/hle/kernel/event.h" | ||||||
| #include "core/hle/service/gsp.h" | #include "core/hle/service/gsp.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hw/gpu.h" | #include "core/hw/gpu.h" | ||||||
|  | @ -60,6 +61,7 @@ void GX_FinishCommand(u32 thread_id) { | ||||||
| 
 | 
 | ||||||
| namespace GSP_GPU { | namespace GSP_GPU { | ||||||
| 
 | 
 | ||||||
|  | Handle g_event_handle = 0; | ||||||
| u32 g_thread_id = 0; | u32 g_thread_id = 0; | ||||||
| 
 | 
 | ||||||
| enum { | enum { | ||||||
|  | @ -96,7 +98,7 @@ void ReadHWRegs(Service::Interface* self) { | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     default: |     default: | ||||||
|         ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr); |         ERROR_LOG(GSP, "unknown register read at address %08X", reg_addr); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -104,7 +106,19 @@ void ReadHWRegs(Service::Interface* self) { | ||||||
| void RegisterInterruptRelayQueue(Service::Interface* self) { | void RegisterInterruptRelayQueue(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Service::GetCommandBuffer(); |     u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|     u32 flags = cmd_buff[1]; |     u32 flags = cmd_buff[1]; | ||||||
|     u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling
 |     u32 event_handle = cmd_buff[3]; | ||||||
|  | 
 | ||||||
|  |     _assert_msg_(GSP, (event_handle != 0), "called, but event is nullptr!"); | ||||||
|  | 
 | ||||||
|  |     g_event_handle = event_handle; | ||||||
|  | 
 | ||||||
|  |     Kernel::SetEventLocked(event_handle, false); | ||||||
|  | 
 | ||||||
|  |     // Hack - This function will permanently set the state of the GSP event such that GPU command 
 | ||||||
|  |     // synchronization barriers always passthrough. Correct solution would be to set this after the 
 | ||||||
|  |     // GPU as processed all queued up commands, but due to the emulator being single-threaded they
 | ||||||
|  |     // will always be ready.
 | ||||||
|  |     Kernel::SetPermanentLock(event_handle, true); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[2] = g_thread_id;          // ThreadID
 |     cmd_buff[2] = g_thread_id;          // ThreadID
 | ||||||
| } | } | ||||||
|  | @ -150,43 +164,43 @@ void TriggerCmdReqQueue(Service::Interface* self) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     default: |     default: | ||||||
|         ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]); |         ERROR_LOG(GSP, "unknown command 0x%08X", cmd_buff[0]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     GX_FinishCommand(g_thread_id); |     GX_FinishCommand(g_thread_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const Interface::FunctionInfo FunctionTable[] = { | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x00010082, NULL,                          "WriteHWRegs"}, |     {0x00010082, nullptr,                       "WriteHWRegs"}, | ||||||
|     {0x00020084, NULL,                          "WriteHWRegsWithMask"}, |     {0x00020084, nullptr,                       "WriteHWRegsWithMask"}, | ||||||
|     {0x00030082, NULL,                          "WriteHWRegRepeat"}, |     {0x00030082, nullptr,                       "WriteHWRegRepeat"}, | ||||||
|     {0x00040080, ReadHWRegs,                    "ReadHWRegs"}, |     {0x00040080, ReadHWRegs,                    "ReadHWRegs"}, | ||||||
|     {0x00050200, NULL,                          "SetBufferSwap"}, |     {0x00050200, nullptr,                       "SetBufferSwap"}, | ||||||
|     {0x00060082, NULL,                          "SetCommandList"}, |     {0x00060082, nullptr,                       "SetCommandList"}, | ||||||
|     {0x000700C2, NULL,                          "RequestDma"}, |     {0x000700C2, nullptr,                       "RequestDma"}, | ||||||
|     {0x00080082, NULL,                          "FlushDataCache"}, |     {0x00080082, nullptr,                       "FlushDataCache"}, | ||||||
|     {0x00090082, NULL,                          "InvalidateDataCache"}, |     {0x00090082, nullptr,                       "InvalidateDataCache"}, | ||||||
|     {0x000A0044, NULL,                          "RegisterInterruptEvents"}, |     {0x000A0044, nullptr,                       "RegisterInterruptEvents"}, | ||||||
|     {0x000B0040, NULL,                          "SetLcdForceBlack"}, |     {0x000B0040, nullptr,                       "SetLcdForceBlack"}, | ||||||
|     {0x000C0000, TriggerCmdReqQueue,            "TriggerCmdReqQueue"}, |     {0x000C0000, TriggerCmdReqQueue,            "TriggerCmdReqQueue"}, | ||||||
|     {0x000D0140, NULL,                          "SetDisplayTransfer"}, |     {0x000D0140, nullptr,                       "SetDisplayTransfer"}, | ||||||
|     {0x000E0180, NULL,                          "SetTextureCopy"}, |     {0x000E0180, nullptr,                       "SetTextureCopy"}, | ||||||
|     {0x000F0200, NULL,                          "SetMemoryFill"}, |     {0x000F0200, nullptr,                       "SetMemoryFill"}, | ||||||
|     {0x00100040, NULL,                          "SetAxiConfigQoSMode"}, |     {0x00100040, nullptr,                       "SetAxiConfigQoSMode"}, | ||||||
|     {0x00110040, NULL,                          "SetPerfLogMode"}, |     {0x00110040, nullptr,                       "SetPerfLogMode"}, | ||||||
|     {0x00120000, NULL,                          "GetPerfLog"}, |     {0x00120000, nullptr,                       "GetPerfLog"}, | ||||||
|     {0x00130042, RegisterInterruptRelayQueue,   "RegisterInterruptRelayQueue"}, |     {0x00130042, RegisterInterruptRelayQueue,   "RegisterInterruptRelayQueue"}, | ||||||
|     {0x00140000, NULL,                          "UnregisterInterruptRelayQueue"}, |     {0x00140000, nullptr,                       "UnregisterInterruptRelayQueue"}, | ||||||
|     {0x00150002, NULL,                          "TryAcquireRight"}, |     {0x00150002, nullptr,                       "TryAcquireRight"}, | ||||||
|     {0x00160042, NULL,                          "AcquireRight"}, |     {0x00160042, nullptr,                       "AcquireRight"}, | ||||||
|     {0x00170000, NULL,                          "ReleaseRight"}, |     {0x00170000, nullptr,                       "ReleaseRight"}, | ||||||
|     {0x00180000, NULL,                          "ImportDisplayCaptureInfo"}, |     {0x00180000, nullptr,                       "ImportDisplayCaptureInfo"}, | ||||||
|     {0x00190000, NULL,                          "SaveVramSysArea"}, |     {0x00190000, nullptr,                       "SaveVramSysArea"}, | ||||||
|     {0x001A0000, NULL,                          "RestoreVramSysArea"}, |     {0x001A0000, nullptr,                       "RestoreVramSysArea"}, | ||||||
|     {0x001B0000, NULL,                          "ResetGpuCore"}, |     {0x001B0000, nullptr,                       "ResetGpuCore"}, | ||||||
|     {0x001C0040, NULL,                          "SetLedForceOff"}, |     {0x001C0040, nullptr,                       "SetLedForceOff"}, | ||||||
|     {0x001D0040, NULL,                          "SetTestCommand"}, |     {0x001D0040, nullptr,                       "SetTestCommand"}, | ||||||
|     {0x001E0080, NULL,                          "SetInternalPriorities"}, |     {0x001E0080, nullptr,                       "SetInternalPriorities"}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  |  | ||||||
|  | @ -13,11 +13,11 @@ | ||||||
| namespace HID_User { | namespace HID_User { | ||||||
| 
 | 
 | ||||||
| const Interface::FunctionInfo FunctionTable[] = { | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x000A0000, NULL, "GetIPCHandles"}, |     {0x000A0000, nullptr, "GetIPCHandles"}, | ||||||
|     {0x00110000, NULL, "EnableAccelerometer"}, |     {0x00110000, nullptr, "EnableAccelerometer"}, | ||||||
|     {0x00130000, NULL, "EnableGyroscopeLow"}, |     {0x00130000, nullptr, "EnableGyroscopeLow"}, | ||||||
|     {0x00150000, NULL, "GetGyroscopeLowRawToDpsCoefficient"}, |     {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, | ||||||
|     {0x00160000, NULL, "GetGyroscopeLowCalibrateParam"}, |     {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  |  | ||||||
							
								
								
									
										32
									
								
								src/core/hle/service/ndm.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/core/hle/service/ndm.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | // Copyright 2014 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "common/log.h" | ||||||
|  | 
 | ||||||
|  | #include "core/hle/hle.h" | ||||||
|  | #include "core/hle/service/ndm.h" | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Namespace NDM_U
 | ||||||
|  | 
 | ||||||
|  | namespace NDM_U { | ||||||
|  | 
 | ||||||
|  | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|  |     {0x00060040, nullptr, "SuspendDaemons"}, | ||||||
|  |     {0x00080040, nullptr, "DisableWifiUsage"}, | ||||||
|  |     {0x00090000, nullptr, "EnableWifiUsage"}, | ||||||
|  |     {0x00140040, nullptr, "OverrideDefaultDaemons"}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Interface class
 | ||||||
|  | 
 | ||||||
|  | Interface::Interface() { | ||||||
|  |     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Interface::~Interface() { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
							
								
								
									
										33
									
								
								src/core/hle/service/ndm.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/core/hle/service/ndm.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | ||||||
|  | // Copyright 2014 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "core/hle/service/service.h" | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Namespace NDM
 | ||||||
|  | 
 | ||||||
|  | // No idea what this is
 | ||||||
|  | 
 | ||||||
|  | namespace NDM_U { | ||||||
|  | 
 | ||||||
|  | class Interface : public Service::Interface { | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  |     Interface(); | ||||||
|  | 
 | ||||||
|  |     ~Interface(); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets the string port name used by CTROS for the service | ||||||
|  |      * @return Port name of service | ||||||
|  |      */ | ||||||
|  |     const char *GetPortName() const { | ||||||
|  |         return "ndm:u"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
|  | @ -12,13 +12,14 @@ | ||||||
| #include "core/hle/service/apt.h" | #include "core/hle/service/apt.h" | ||||||
| #include "core/hle/service/gsp.h" | #include "core/hle/service/gsp.h" | ||||||
| #include "core/hle/service/hid.h" | #include "core/hle/service/hid.h" | ||||||
|  | #include "core/hle/service/ndm.h" | ||||||
| #include "core/hle/service/srv.h" | #include "core/hle/service/srv.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| 
 | 
 | ||||||
| namespace Service { | namespace Service { | ||||||
| 
 | 
 | ||||||
| Manager* g_manager = NULL;  ///< Service manager
 | Manager* g_manager = nullptr;  ///< Service manager
 | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Service Manager class
 | // Service Manager class
 | ||||||
|  | @ -55,7 +56,7 @@ Interface* Manager::FetchFromHandle(Handle handle) { | ||||||
| Interface* Manager::FetchFromPortName(std::string port_name) { | Interface* Manager::FetchFromPortName(std::string port_name) { | ||||||
|     auto itr = m_port_map.find(port_name); |     auto itr = m_port_map.find(port_name); | ||||||
|     if (itr == m_port_map.end()) { |     if (itr == m_port_map.end()) { | ||||||
|         return NULL; |         return nullptr; | ||||||
|     } |     } | ||||||
|     return FetchFromHandle(itr->second); |     return FetchFromHandle(itr->second); | ||||||
| } | } | ||||||
|  | @ -72,14 +73,15 @@ void Init() { | ||||||
|     g_manager->AddService(new APT_U::Interface); |     g_manager->AddService(new APT_U::Interface); | ||||||
|     g_manager->AddService(new GSP_GPU::Interface); |     g_manager->AddService(new GSP_GPU::Interface); | ||||||
|     g_manager->AddService(new HID_User::Interface); |     g_manager->AddService(new HID_User::Interface); | ||||||
|  |     g_manager->AddService(new NDM_U::Interface); | ||||||
| 
 | 
 | ||||||
|     NOTICE_LOG(HLE, "Services initialized OK"); |     NOTICE_LOG(HLE, "initialized OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Shutdown ServiceManager
 | /// Shutdown ServiceManager
 | ||||||
| void Shutdown() { | void Shutdown() { | ||||||
|     delete g_manager; |     delete g_manager; | ||||||
|     NOTICE_LOG(HLE, "Services shutdown OK"); |     NOTICE_LOG(HLE, "shutdown OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -39,8 +39,8 @@ class Interface  : public Kernel::Object { | ||||||
|     friend class Manager; |     friend class Manager; | ||||||
| public: | public: | ||||||
|      |      | ||||||
|     const char *GetName() { return GetPortName(); } |     const char *GetName() const { return GetPortName(); } | ||||||
|     const char *GetTypeName() { return GetPortName(); } |     const char *GetTypeName() const { return GetPortName(); } | ||||||
| 
 | 
 | ||||||
|     static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } |     static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } | ||||||
|     Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } |     Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } | ||||||
|  | @ -76,22 +76,31 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Called when svcSendSyncRequest is called, loads command buffer and executes comand |      * Synchronize kernel object  | ||||||
|      * @return Return result of svcSendSyncRequest passed back to user app |      * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||||||
|  |      * @return Result of operation, 0 on success, otherwise error code | ||||||
|      */ |      */ | ||||||
|     Result Sync() { |     Result SyncRequest(bool* wait) { | ||||||
|         u32* cmd_buff = GetCommandBuffer(); |         u32* cmd_buff = GetCommandBuffer(); | ||||||
|         auto itr = m_functions.find(cmd_buff[0]); |         auto itr = m_functions.find(cmd_buff[0]); | ||||||
| 
 | 
 | ||||||
|         if (itr == m_functions.end()) { |         if (itr == m_functions.end()) { | ||||||
|             ERROR_LOG(OSHLE, "Unknown/unimplemented function: port = %s, command = 0x%08X!",  |             ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X",  | ||||||
|                 GetPortName(), cmd_buff[0]); |                 GetPortName(), cmd_buff[0]); | ||||||
|             return -1; | 
 | ||||||
|  |             // TODO(bunnei): Hack - ignore error
 | ||||||
|  |             u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|  |             cmd_buff[1] = 0; | ||||||
|  |             return 0;  | ||||||
|         } |         } | ||||||
|         if (itr->second.func == NULL) { |         if (itr->second.func == nullptr) { | ||||||
|             ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!",  |             ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",  | ||||||
|                 GetPortName(), itr->second.name.c_str()); |                 GetPortName(), itr->second.name.c_str()); | ||||||
|             return -1; | 
 | ||||||
|  |             // TODO(bunnei): Hack - ignore error
 | ||||||
|  |             u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|  |             cmd_buff[1] = 0; | ||||||
|  |             return 0;  | ||||||
|         }  |         }  | ||||||
| 
 | 
 | ||||||
|         itr->second.func(this); |         itr->second.func(this); | ||||||
|  | @ -99,6 +108,17 @@ public: | ||||||
|         return 0; // TODO: Implement return from actual function
 |         return 0; // TODO: Implement return from actual function
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Wait for kernel object to synchronize | ||||||
|  |      * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||||||
|  |      * @return Result of operation, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     Result WaitSynchronization(bool* wait) { | ||||||
|  |         // TODO(bunnei): ImplementMe
 | ||||||
|  |         ERROR_LOG(OSHLE, "unimplemented function"); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  |  | ||||||
|  | @ -5,21 +5,28 @@ | ||||||
| #include "core/hle/hle.h" | #include "core/hle/hle.h" | ||||||
| #include "core/hle/service/srv.h" | #include "core/hle/service/srv.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| 
 | #include "core/hle/kernel/mutex.h" | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Namespace SRV
 | // Namespace SRV
 | ||||||
| 
 | 
 | ||||||
| namespace SRV { | namespace SRV { | ||||||
| 
 | 
 | ||||||
|  | Handle g_mutex = 0; | ||||||
|  | 
 | ||||||
| void Initialize(Service::Interface* self) { | void Initialize(Service::Interface* self) { | ||||||
|     NOTICE_LOG(OSHLE, "SRV::Sync - Initialize"); |     DEBUG_LOG(OSHLE, "called"); | ||||||
|  |     if (!g_mutex) { | ||||||
|  |         g_mutex = Kernel::CreateMutex(true, "SRV:Lock"); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetProcSemaphore(Service::Interface* self) { | void GetProcSemaphore(Service::Interface* self) { | ||||||
|  |     DEBUG_LOG(OSHLE, "called"); | ||||||
|     // Get process semaphore?
 |     // Get process semaphore?
 | ||||||
|     u32* cmd_buff = Service::GetCommandBuffer(); |     u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|     cmd_buff[3] = 0xDEADBEEF; // Return something... 0 == NULL, raises an exception
 |     cmd_buff[1] = 0;        // No error
 | ||||||
|  |     cmd_buff[3] = g_mutex;  // Return something... 0 == nullptr, raises an exception
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetServiceHandle(Service::Interface* self) { | void GetServiceHandle(Service::Interface* self) { | ||||||
|  | @ -29,25 +36,21 @@ void GetServiceHandle(Service::Interface* self) { | ||||||
|     std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); |     std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); | ||||||
|     Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); |     Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); | ||||||
| 
 | 
 | ||||||
|     NOTICE_LOG(OSHLE, "SRV::Sync - GetHandle - port: %s, handle: 0x%08X", port_name.c_str(),  |     if (nullptr != service) { | ||||||
|         service->GetHandle()); |  | ||||||
| 
 |  | ||||||
|     if (NULL != service) { |  | ||||||
|         cmd_buff[3] = service->GetHandle(); |         cmd_buff[3] = service->GetHandle(); | ||||||
|  |         DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); | ||||||
|     } else { |     } else { | ||||||
|         ERROR_LOG(OSHLE, "Service %s does not exist", port_name.c_str()); |         ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); | ||||||
|         res = -1; |         res = -1; | ||||||
|     } |     } | ||||||
|     cmd_buff[1] = res; |     cmd_buff[1] = res; | ||||||
| 
 |  | ||||||
|     //return res;
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const Interface::FunctionInfo FunctionTable[] = { | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x00010002, Initialize,        "Initialize"}, |     {0x00010002, Initialize,        "Initialize"}, | ||||||
|     {0x00020000, GetProcSemaphore,  "GetProcSemaphore"}, |     {0x00020000, GetProcSemaphore,  "GetProcSemaphore"}, | ||||||
|     {0x00030100, NULL,              "RegisterService"}, |     {0x00030100, nullptr,           "RegisterService"}, | ||||||
|     {0x000400C0, NULL,              "UnregisterService"}, |     {0x000400C0, nullptr,           "UnregisterService"}, | ||||||
|     {0x00050100, GetServiceHandle,  "GetServiceHandle"}, |     {0x00050100, GetServiceHandle,  "GetServiceHandle"}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,12 +26,6 @@ public: | ||||||
|         return "srv:"; |         return "srv:"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |  | ||||||
|      * Called when svcSendSyncRequest is called, loads command buffer and executes comand |  | ||||||
|      * @return Return result of svcSendSyncRequest passed back to user app |  | ||||||
|      */ |  | ||||||
|     Result Sync(); |  | ||||||
| 
 |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "core/mem_map.h" | #include "core/mem_map.h" | ||||||
| 
 | 
 | ||||||
|  | #include "core/hle/kernel/event.h" | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| #include "core/hle/kernel/mutex.h" | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
|  | @ -16,7 +17,6 @@ | ||||||
| #include "core/hle/function_wrappers.h" | #include "core/hle/function_wrappers.h" | ||||||
| #include "core/hle/svc.h" | #include "core/hle/svc.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| #include "core/hle/kernel/thread.h" |  | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Namespace SVC
 | // Namespace SVC
 | ||||||
|  | @ -34,40 +34,32 @@ enum MapMemoryPermission { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Map application or GSP heap memory
 | /// Map application or GSP heap memory
 | ||||||
| Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | ||||||
|     u32* outaddr = (u32*)_outaddr; |     DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",  | ||||||
|     u32 virtual_address = 0x00000000; |  | ||||||
| 
 |  | ||||||
|     DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",  |  | ||||||
|         operation, addr0, addr1, size, permissions); |         operation, addr0, addr1, size, permissions); | ||||||
| 
 | 
 | ||||||
|     switch (operation) { |     switch (operation) { | ||||||
| 
 | 
 | ||||||
|     // Map normal heap memory
 |     // Map normal heap memory
 | ||||||
|     case MEMORY_OPERATION_HEAP: |     case MEMORY_OPERATION_HEAP: | ||||||
|         virtual_address = Memory::MapBlock_Heap(size, operation, permissions); |         *out_addr = Memory::MapBlock_Heap(size, operation, permissions); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     // Map GSP heap memory
 |     // Map GSP heap memory
 | ||||||
|     case MEMORY_OPERATION_GSP_HEAP: |     case MEMORY_OPERATION_GSP_HEAP: | ||||||
|         virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions); |         *out_addr = Memory::MapBlock_HeapGSP(size, operation, permissions); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     // Unknown ControlMemory operation
 |     // Unknown ControlMemory operation
 | ||||||
|     default: |     default: | ||||||
|         ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); |         ERROR_LOG(SVC, "unknown operation=0x%08X", operation); | ||||||
|     } |     } | ||||||
|     if (NULL != outaddr) { |  | ||||||
|         *outaddr = virtual_address; |  | ||||||
|     } |  | ||||||
|     Core::g_app_core->SetReg(1, virtual_address); |  | ||||||
| 
 |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Maps a memory block to specified address
 | /// Maps a memory block to specified address
 | ||||||
| Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { | Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { | ||||||
|     DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",  |     DEBUG_LOG(SVC, "called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",  | ||||||
|         memblock, addr, mypermissions, otherpermission); |         memblock, addr, mypermissions, otherpermission); | ||||||
|     switch (mypermissions) { |     switch (mypermissions) { | ||||||
|     case MEMORY_PERMISSION_NORMAL: |     case MEMORY_PERMISSION_NORMAL: | ||||||
|  | @ -76,88 +68,146 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper | ||||||
|         Memory::MapBlock_Shared(memblock, addr, mypermissions); |         Memory::MapBlock_Shared(memblock, addr, mypermissions); | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
|         ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); |         ERROR_LOG(OSHLE, "unknown permissions=0x%08X", mypermissions); | ||||||
|     } |     } | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Connect to an OS service given the port name, returns the handle to the port to out
 | /// Connect to an OS service given the port name, returns the handle to the port to out
 | ||||||
| Result ConnectToPort(void* out, const char* port_name) { | Result ConnectToPort(Handle* out, const char* port_name) { | ||||||
|     Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); |     Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); | ||||||
|     if (service) { | 
 | ||||||
|         Core::g_app_core->SetReg(1, service->GetHandle()); |     DEBUG_LOG(SVC, "called port_name=%s", port_name); | ||||||
|     } else { |     _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!"); | ||||||
|         PanicYesNo("ConnectToPort called port_name=%s, but it is not implemented!", port_name); | 
 | ||||||
|     } |     *out = service->GetHandle(); | ||||||
|     DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Synchronize to an OS service
 | /// Synchronize to an OS service
 | ||||||
| Result SendSyncRequest(Handle handle) { | Result SendSyncRequest(Handle handle) { | ||||||
|     DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X"); |     Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); | ||||||
|     Service::Interface* service = Service::g_manager->FetchFromHandle(handle); | 
 | ||||||
|     service->Sync(); |     _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); | ||||||
|     return 0; |     DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName()); | ||||||
|  | 
 | ||||||
|  |     bool wait = false; | ||||||
|  |     Result res = object->SyncRequest(&wait); | ||||||
|  |     if (wait) { | ||||||
|  |         Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Close a handle
 | /// Close a handle
 | ||||||
| Result CloseHandle(Handle handle) { | Result CloseHandle(Handle handle) { | ||||||
|     // ImplementMe
 |     // ImplementMe
 | ||||||
|     DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); |     ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Wait for a handle to synchronize, timeout after the specified nanoseconds
 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds
 | ||||||
| Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | ||||||
|     DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d",  |     // TODO(bunnei): Do something with nano_seconds, currently ignoring this
 | ||||||
|         handle, nano_seconds); |     bool wait = false; | ||||||
|     Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
 |     bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
 | ||||||
|  | 
 | ||||||
|  |     Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); | ||||||
|  | 
 | ||||||
|  |     DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName(),  | ||||||
|  |             object->GetName(), nano_seconds); | ||||||
|  | 
 | ||||||
|  |     _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); | ||||||
|  | 
 | ||||||
|  |     Result res = object->WaitSynchronization(&wait); | ||||||
|  | 
 | ||||||
|  |     // Check for next thread to schedule
 | ||||||
|  |     if (wait) { | ||||||
|  |         HLE::Reschedule(__func__); | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
 |     return res; | ||||||
| Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) { | } | ||||||
|     s32* out = (s32*)_out; |  | ||||||
|     Handle* handles = (Handle*)_handles; |  | ||||||
| 
 | 
 | ||||||
|     DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s",  | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
 | ||||||
|  | Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all,  | ||||||
|  |     s64 nano_seconds) { | ||||||
|  |     // TODO(bunnei): Do something with nano_seconds, currently ignoring this
 | ||||||
|  |     bool unlock_all = true; | ||||||
|  |     bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
 | ||||||
|  | 
 | ||||||
|  |     DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d",  | ||||||
|         handle_count, (wait_all ? "true" : "false"), nano_seconds); |         handle_count, (wait_all ? "true" : "false"), nano_seconds); | ||||||
| 
 | 
 | ||||||
|     for (u32 i = 0; i < handle_count; i++) { |     // Iterate through each handle, synchronize kernel object
 | ||||||
|         DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); |     for (s32 i = 0; i < handle_count; i++) { | ||||||
|  |         bool wait = false; | ||||||
|  |         Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); | ||||||
|  | 
 | ||||||
|  |         _assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object " | ||||||
|  |             "is nullptr!", handles[i]); | ||||||
|  | 
 | ||||||
|  |         DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName(),  | ||||||
|  |             object->GetName()); | ||||||
|  | 
 | ||||||
|  |         Result res = object->WaitSynchronization(&wait); | ||||||
|  | 
 | ||||||
|  |         if (!wait && !wait_all) { | ||||||
|  |             *out = i; | ||||||
|  |             return 0; | ||||||
|  |         } else { | ||||||
|  |             unlock_all = false; | ||||||
|         } |         } | ||||||
|     Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
 |     } | ||||||
|  | 
 | ||||||
|  |     if (wait_all && unlock_all) { | ||||||
|  |         *out = handle_count; | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Check for next thread to schedule
 | ||||||
|  |     HLE::Reschedule(__func__); | ||||||
|  | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Create an address arbiter (to allocate access to shared resources)
 | /// Create an address arbiter (to allocate access to shared resources)
 | ||||||
| Result CreateAddressArbiter(void* arbiter) { | Result CreateAddressArbiter(void* arbiter) { | ||||||
|     // ImplementMe
 |     ERROR_LOG(SVC, "(UNIMPLEMENTED) called"); | ||||||
|     DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called"); |  | ||||||
|     Core::g_app_core->SetReg(1, 0xFABBDADD); |     Core::g_app_core->SetReg(1, 0xFABBDADD); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Arbitrate address
 | ||||||
|  | Result ArbitrateAddress(Handle arbiter, u32 addr, u32 _type, u32 value, s64 nanoseconds) { | ||||||
|  |     ERROR_LOG(SVC, "(UNIMPLEMENTED) called"); | ||||||
|  |     ArbitrationType type = (ArbitrationType)_type; | ||||||
|  |     Memory::Write32(addr, type); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Used to output a message on a debug hardware unit - does nothing on a retail unit
 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit
 | ||||||
| void OutputDebugString(const char* string) { | void OutputDebugString(const char* string) { | ||||||
|     NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string); |     OS_LOG(SVC, "%s", string); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Get resource limit
 | /// Get resource limit
 | ||||||
| Result GetResourceLimit(void* resource_limit, Handle process) { | Result GetResourceLimit(Handle* resource_limit, Handle process) { | ||||||
|     // With regards to proceess values:
 |     // With regards to proceess values:
 | ||||||
|     // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for 
 |     // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for 
 | ||||||
|     // the current KThread.
 |     // the current KThread.
 | ||||||
|     DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); |     *resource_limit = 0xDEADBEEF; | ||||||
|     Core::g_app_core->SetReg(1, 0xDEADBEEF); |     ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Get resource limit current values
 | /// Get resource limit current values
 | ||||||
| Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { | Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,  | ||||||
|     //s64* values = (s64*)_values;
 |     s32 name_count) { | ||||||
|     DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", |     ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", | ||||||
|         resource_limit, names, name_count); |         resource_limit, names, name_count); | ||||||
|     Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
 |     Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
 | ||||||
|     return 0; |     return 0; | ||||||
|  | @ -180,179 +230,234 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p | ||||||
| 
 | 
 | ||||||
|     Core::g_app_core->SetReg(1, thread); |     Core::g_app_core->SetReg(1, thread); | ||||||
| 
 | 
 | ||||||
|     DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " |     DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " | ||||||
|         "threadpriority=0x%08X, processorid=0x%08X : created handle 0x%08X", entry_point,  |         "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,  | ||||||
|         name.c_str(), arg, stack_top, priority, processor_id, thread); |         name.c_str(), arg, stack_top, priority, processor_id, thread); | ||||||
|      |      | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Called when a thread exits
 | ||||||
|  | u32 ExitThread() { | ||||||
|  |     Handle thread = Kernel::GetCurrentThreadHandle(); | ||||||
|  | 
 | ||||||
|  |     DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C
 | ||||||
|  | 
 | ||||||
|  |     Kernel::StopThread(thread, __func__); | ||||||
|  |     HLE::Reschedule(__func__); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Gets the priority for the specified thread
 | ||||||
|  | Result GetThreadPriority(s32* priority, Handle handle) { | ||||||
|  |     *priority = Kernel::GetThreadPriority(handle); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Sets the priority for the specified thread
 | ||||||
|  | Result SetThreadPriority(Handle handle, s32 priority) { | ||||||
|  |     return Kernel::SetThreadPriority(handle, priority); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Create a mutex
 | /// Create a mutex
 | ||||||
| Result CreateMutex(void* _mutex, u32 initial_locked) { | Result CreateMutex(Handle* mutex, u32 initial_locked) { | ||||||
|     Handle* mutex = (Handle*)_mutex; |  | ||||||
|     *mutex = Kernel::CreateMutex((initial_locked != 0)); |     *mutex = Kernel::CreateMutex((initial_locked != 0)); | ||||||
|     Core::g_app_core->SetReg(1, *mutex); |     DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X",  | ||||||
|     DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s : created handle 0x%08X",  |  | ||||||
|         initial_locked ? "true" : "false", *mutex); |         initial_locked ? "true" : "false", *mutex); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Release a mutex
 | /// Release a mutex
 | ||||||
| Result ReleaseMutex(Handle handle) { | Result ReleaseMutex(Handle handle) { | ||||||
|     DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle); |     DEBUG_LOG(SVC, "called handle=0x%08X", handle); | ||||||
|  |     _assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!"); | ||||||
|     Kernel::ReleaseMutex(handle); |     Kernel::ReleaseMutex(handle); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Get current thread ID
 | /// Get current thread ID
 | ||||||
| Result GetThreadId(void* thread_id, u32 thread) { | Result GetThreadId(u32* thread_id, Handle thread) { | ||||||
|     DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread); |     ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Query memory
 | /// Query memory
 | ||||||
| Result QueryMemory(void *_info, void *_out, u32 addr) { | Result QueryMemory(void* info, void* out, u32 addr) { | ||||||
|     MemoryInfo* info = (MemoryInfo*) _info; |     ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); | ||||||
|     PageInfo* out = (PageInfo*) _out; |  | ||||||
|     DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr); |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Create an event
 | /// Create an event
 | ||||||
| Result CreateEvent(void* _event, u32 reset_type) { | Result CreateEvent(Handle* evt, u32 reset_type) { | ||||||
|     Handle* event = (Handle*)_event; |     *evt = Kernel::CreateEvent((ResetType)reset_type); | ||||||
|     DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type); |     DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X",  | ||||||
|     Core::g_app_core->SetReg(1, 0xBADC0DE0); |         reset_type, *evt); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Duplicates a kernel handle
 | ||||||
|  | Result DuplicateHandle(Handle* out, Handle handle) { | ||||||
|  |     DEBUG_LOG(SVC, "called handle=0x%08X", handle); | ||||||
|  | 
 | ||||||
|  |     // Translate kernel handles -> real handles
 | ||||||
|  |     if (handle == Kernel::CurrentThread) { | ||||||
|  |         handle = Kernel::GetCurrentThreadHandle(); | ||||||
|  |     } | ||||||
|  |     _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess), | ||||||
|  |         "(UNIMPLEMENTED) process handle duplication!"); | ||||||
|  |      | ||||||
|  |     // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate.
 | ||||||
|  |     *out = handle; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Signals an event
 | ||||||
|  | Result SignalEvent(Handle evt) { | ||||||
|  |     Result res = Kernel::SignalEvent(evt); | ||||||
|  |     DEBUG_LOG(SVC, "called event=0x%08X", evt); | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Clears an event
 | ||||||
|  | Result ClearEvent(Handle evt) { | ||||||
|  |     Result res = Kernel::ClearEvent(evt); | ||||||
|  |     DEBUG_LOG(SVC, "called event=0x%08X", evt); | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Sleep the current thread
 | ||||||
|  | void SleepThread(s64 nanoseconds) { | ||||||
|  |     DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const HLE::FunctionDef SVC_Table[] = { | const HLE::FunctionDef SVC_Table[] = { | ||||||
|     {0x00,  NULL,                                       "Unknown"}, |     {0x00, nullptr,                         "Unknown"}, | ||||||
|     {0x01,  WrapI_VUUUUU<ControlMemory>,                "ControlMemory"}, |     {0x01, HLE::Wrap<ControlMemory>,        "ControlMemory"}, | ||||||
|     {0x02,  WrapI_VVU<QueryMemory>,                     "QueryMemory"}, |     {0x02, HLE::Wrap<QueryMemory>,          "QueryMemory"}, | ||||||
|     {0x03,  NULL,                                       "ExitProcess"}, |     {0x03, nullptr,                         "ExitProcess"}, | ||||||
|     {0x04,  NULL,                                       "GetProcessAffinityMask"}, |     {0x04, nullptr,                         "GetProcessAffinityMask"}, | ||||||
|     {0x05,  NULL,                                       "SetProcessAffinityMask"}, |     {0x05, nullptr,                         "SetProcessAffinityMask"}, | ||||||
|     {0x06,  NULL,                                       "GetProcessIdealProcessor"}, |     {0x06, nullptr,                         "GetProcessIdealProcessor"}, | ||||||
|     {0x07,  NULL,                                       "SetProcessIdealProcessor"}, |     {0x07, nullptr,                         "SetProcessIdealProcessor"}, | ||||||
|     {0x08,  WrapI_UUUUU<CreateThread>,                  "CreateThread"}, |     {0x08, HLE::Wrap<CreateThread>,         "CreateThread"}, | ||||||
|     {0x09,  NULL,                                       "ExitThread"}, |     {0x09, HLE::Wrap<ExitThread>,           "ExitThread"}, | ||||||
|     {0x0A,  NULL,                                       "SleepThread"}, |     {0x0A, HLE::Wrap<SleepThread>,          "SleepThread"}, | ||||||
|     {0x0B,  NULL,                                       "GetThreadPriority"}, |     {0x0B, HLE::Wrap<GetThreadPriority>,    "GetThreadPriority"}, | ||||||
|     {0x0C,  NULL,                                       "SetThreadPriority"}, |     {0x0C, HLE::Wrap<SetThreadPriority>,    "SetThreadPriority"}, | ||||||
|     {0x0D,  NULL,                                       "GetThreadAffinityMask"}, |     {0x0D, nullptr,                         "GetThreadAffinityMask"}, | ||||||
|     {0x0E,  NULL,                                       "SetThreadAffinityMask"}, |     {0x0E, nullptr,                         "SetThreadAffinityMask"}, | ||||||
|     {0x0F,  NULL,                                       "GetThreadIdealProcessor"}, |     {0x0F, nullptr,                         "GetThreadIdealProcessor"}, | ||||||
|     {0x10,  NULL,                                       "SetThreadIdealProcessor"}, |     {0x10, nullptr,                         "SetThreadIdealProcessor"}, | ||||||
|     {0x11,  NULL,                                       "GetCurrentProcessorNumber"}, |     {0x11, nullptr,                         "GetCurrentProcessorNumber"}, | ||||||
|     {0x12,  NULL,                                       "Run"}, |     {0x12, nullptr,                         "Run"}, | ||||||
|     {0x13,  WrapI_VU<CreateMutex>,                      "CreateMutex"}, |     {0x13, HLE::Wrap<CreateMutex>,          "CreateMutex"}, | ||||||
|     {0x14,  WrapI_U<ReleaseMutex>,                      "ReleaseMutex"}, |     {0x14, HLE::Wrap<ReleaseMutex>,         "ReleaseMutex"}, | ||||||
|     {0x15,  NULL,                                       "CreateSemaphore"}, |     {0x15, nullptr,                         "CreateSemaphore"}, | ||||||
|     {0x16,  NULL,                                       "ReleaseSemaphore"}, |     {0x16, nullptr,                         "ReleaseSemaphore"}, | ||||||
|     {0x17,  WrapI_VU<CreateEvent>,                      "CreateEvent"}, |     {0x17, HLE::Wrap<CreateEvent>,          "CreateEvent"}, | ||||||
|     {0x18,  NULL,                                       "SignalEvent"}, |     {0x18, HLE::Wrap<SignalEvent>,          "SignalEvent"}, | ||||||
|     {0x19,  NULL,                                       "ClearEvent"}, |     {0x19, HLE::Wrap<ClearEvent>,           "ClearEvent"}, | ||||||
|     {0x1A,  NULL,                                       "CreateTimer"}, |     {0x1A, nullptr,                         "CreateTimer"}, | ||||||
|     {0x1B,  NULL,                                       "SetTimer"}, |     {0x1B, nullptr,                         "SetTimer"}, | ||||||
|     {0x1C,  NULL,                                       "CancelTimer"}, |     {0x1C, nullptr,                         "CancelTimer"}, | ||||||
|     {0x1D,  NULL,                                       "ClearTimer"}, |     {0x1D, nullptr,                         "ClearTimer"}, | ||||||
|     {0x1E,  NULL,                                       "CreateMemoryBlock"}, |     {0x1E, nullptr,                         "CreateMemoryBlock"}, | ||||||
|     {0x1F,  WrapI_UUUU<MapMemoryBlock>,                 "MapMemoryBlock"}, |     {0x1F, HLE::Wrap<MapMemoryBlock>,       "MapMemoryBlock"}, | ||||||
|     {0x20,  NULL,                                       "UnmapMemoryBlock"}, |     {0x20, nullptr,                         "UnmapMemoryBlock"}, | ||||||
|     {0x21,  WrapI_V<CreateAddressArbiter>,              "CreateAddressArbiter"}, |     {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"}, | ||||||
|     {0x22,  NULL,                                       "ArbitrateAddress"}, |     {0x22, HLE::Wrap<ArbitrateAddress>,     "ArbitrateAddress"}, | ||||||
|     {0x23,  WrapI_U<CloseHandle>,                       "CloseHandle"}, |     {0x23, HLE::Wrap<CloseHandle>,          "CloseHandle"}, | ||||||
|     {0x24,  WrapI_US64<WaitSynchronization1>,           "WaitSynchronization1"}, |     {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"}, | ||||||
|     {0x25,  WrapI_VVUUS64<WaitSynchronizationN>,        "WaitSynchronizationN"}, |     {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"}, | ||||||
|     {0x26,  NULL,                                       "SignalAndWait"}, |     {0x26, nullptr,                         "SignalAndWait"}, | ||||||
|     {0x27,  NULL,                                       "DuplicateHandle"}, |     {0x27, HLE::Wrap<DuplicateHandle>,      "DuplicateHandle"}, | ||||||
|     {0x28,  NULL,                                       "GetSystemTick"}, |     {0x28, nullptr,                         "GetSystemTick"}, | ||||||
|     {0x29,  NULL,                                       "GetHandleInfo"}, |     {0x29, nullptr,                         "GetHandleInfo"}, | ||||||
|     {0x2A,  NULL,                                       "GetSystemInfo"}, |     {0x2A, nullptr,                         "GetSystemInfo"}, | ||||||
|     {0x2B,  NULL,                                       "GetProcessInfo"}, |     {0x2B, nullptr,                         "GetProcessInfo"}, | ||||||
|     {0x2C,  NULL,                                       "GetThreadInfo"}, |     {0x2C, nullptr,                         "GetThreadInfo"}, | ||||||
|     {0x2D,  WrapI_VC<ConnectToPort>,                    "ConnectToPort"}, |     {0x2D, HLE::Wrap<ConnectToPort>,        "ConnectToPort"}, | ||||||
|     {0x2E,  NULL,                                       "SendSyncRequest1"}, |     {0x2E, nullptr,                         "SendSyncRequest1"}, | ||||||
|     {0x2F,  NULL,                                       "SendSyncRequest2"}, |     {0x2F, nullptr,                         "SendSyncRequest2"}, | ||||||
|     {0x30,  NULL,                                       "SendSyncRequest3"}, |     {0x30, nullptr,                         "SendSyncRequest3"}, | ||||||
|     {0x31,  NULL,                                       "SendSyncRequest4"}, |     {0x31, nullptr,                         "SendSyncRequest4"}, | ||||||
|     {0x32,  WrapI_U<SendSyncRequest>,                   "SendSyncRequest"}, |     {0x32, HLE::Wrap<SendSyncRequest>,      "SendSyncRequest"}, | ||||||
|     {0x33,  NULL,                                       "OpenProcess"}, |     {0x33, nullptr,                         "OpenProcess"}, | ||||||
|     {0x34,  NULL,                                       "OpenThread"}, |     {0x34, nullptr,                         "OpenThread"}, | ||||||
|     {0x35,  NULL,                                       "GetProcessId"}, |     {0x35, nullptr,                         "GetProcessId"}, | ||||||
|     {0x36,  NULL,                                       "GetProcessIdOfThread"}, |     {0x36, nullptr,                         "GetProcessIdOfThread"}, | ||||||
|     {0x37,  WrapI_VU<GetThreadId>,                      "GetThreadId"}, |     {0x37, HLE::Wrap<GetThreadId>,          "GetThreadId"}, | ||||||
|     {0x38,  WrapI_VU<GetResourceLimit>,                 "GetResourceLimit"}, |     {0x38, HLE::Wrap<GetResourceLimit>,     "GetResourceLimit"}, | ||||||
|     {0x39,  NULL,                                       "GetResourceLimitLimitValues"}, |     {0x39, nullptr,                         "GetResourceLimitLimitValues"}, | ||||||
|     {0x3A,  WrapI_VUVI<GetResourceLimitCurrentValues>,  "GetResourceLimitCurrentValues"}, |     {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, | ||||||
|     {0x3B,  NULL,                                       "GetThreadContext"}, |     {0x3B, nullptr,                         "GetThreadContext"}, | ||||||
|     {0x3C,  NULL,                                       "Break"}, |     {0x3C, nullptr,                         "Break"}, | ||||||
|     {0x3D,  WrapV_C<OutputDebugString>,                 "OutputDebugString"}, |     {0x3D, HLE::Wrap<OutputDebugString>,    "OutputDebugString"}, | ||||||
|     {0x3E,  NULL,                                       "ControlPerformanceCounter"}, |     {0x3E, nullptr,                         "ControlPerformanceCounter"}, | ||||||
|     {0x3F,  NULL,                                       "Unknown"}, |     {0x3F, nullptr,                         "Unknown"}, | ||||||
|     {0x40,  NULL,                                       "Unknown"}, |     {0x40, nullptr,                         "Unknown"}, | ||||||
|     {0x41,  NULL,                                       "Unknown"}, |     {0x41, nullptr,                         "Unknown"}, | ||||||
|     {0x42,  NULL,                                       "Unknown"}, |     {0x42, nullptr,                         "Unknown"}, | ||||||
|     {0x43,  NULL,                                       "Unknown"}, |     {0x43, nullptr,                         "Unknown"}, | ||||||
|     {0x44,  NULL,                                       "Unknown"}, |     {0x44, nullptr,                         "Unknown"}, | ||||||
|     {0x45,  NULL,                                       "Unknown"}, |     {0x45, nullptr,                         "Unknown"}, | ||||||
|     {0x46,  NULL,                                       "Unknown"}, |     {0x46, nullptr,                         "Unknown"}, | ||||||
|     {0x47,  NULL,                                       "CreatePort"}, |     {0x47, nullptr,                         "CreatePort"}, | ||||||
|     {0x48,  NULL,                                       "CreateSessionToPort"}, |     {0x48, nullptr,                         "CreateSessionToPort"}, | ||||||
|     {0x49,  NULL,                                       "CreateSession"}, |     {0x49, nullptr,                         "CreateSession"}, | ||||||
|     {0x4A,  NULL,                                       "AcceptSession"}, |     {0x4A, nullptr,                         "AcceptSession"}, | ||||||
|     {0x4B,  NULL,                                       "ReplyAndReceive1"}, |     {0x4B, nullptr,                         "ReplyAndReceive1"}, | ||||||
|     {0x4C,  NULL,                                       "ReplyAndReceive2"}, |     {0x4C, nullptr,                         "ReplyAndReceive2"}, | ||||||
|     {0x4D,  NULL,                                       "ReplyAndReceive3"}, |     {0x4D, nullptr,                         "ReplyAndReceive3"}, | ||||||
|     {0x4E,  NULL,                                       "ReplyAndReceive4"}, |     {0x4E, nullptr,                         "ReplyAndReceive4"}, | ||||||
|     {0x4F,  NULL,                                       "ReplyAndReceive"}, |     {0x4F, nullptr,                         "ReplyAndReceive"}, | ||||||
|     {0x50,  NULL,                                       "BindInterrupt"}, |     {0x50, nullptr,                         "BindInterrupt"}, | ||||||
|     {0x51,  NULL,                                       "UnbindInterrupt"}, |     {0x51, nullptr,                         "UnbindInterrupt"}, | ||||||
|     {0x52,  NULL,                                       "InvalidateProcessDataCache"}, |     {0x52, nullptr,                         "InvalidateProcessDataCache"}, | ||||||
|     {0x53,  NULL,                                       "StoreProcessDataCache"}, |     {0x53, nullptr,                         "StoreProcessDataCache"}, | ||||||
|     {0x54,  NULL,                                       "FlushProcessDataCache"}, |     {0x54, nullptr,                         "FlushProcessDataCache"}, | ||||||
|     {0x55,  NULL,                                       "StartInterProcessDma"}, |     {0x55, nullptr,                         "StartInterProcessDma"}, | ||||||
|     {0x56,  NULL,                                       "StopDma"}, |     {0x56, nullptr,                         "StopDma"}, | ||||||
|     {0x57,  NULL,                                       "GetDmaState"}, |     {0x57, nullptr,                         "GetDmaState"}, | ||||||
|     {0x58,  NULL,                                       "RestartDma"}, |     {0x58, nullptr,                         "RestartDma"}, | ||||||
|     {0x59,  NULL,                                       "Unknown"}, |     {0x59, nullptr,                         "Unknown"}, | ||||||
|     {0x5A,  NULL,                                       "Unknown"}, |     {0x5A, nullptr,                         "Unknown"}, | ||||||
|     {0x5B,  NULL,                                       "Unknown"}, |     {0x5B, nullptr,                         "Unknown"}, | ||||||
|     {0x5C,  NULL,                                       "Unknown"}, |     {0x5C, nullptr,                         "Unknown"}, | ||||||
|     {0x5D,  NULL,                                       "Unknown"}, |     {0x5D, nullptr,                         "Unknown"}, | ||||||
|     {0x5E,  NULL,                                       "Unknown"}, |     {0x5E, nullptr,                         "Unknown"}, | ||||||
|     {0x5F,  NULL,                                       "Unknown"}, |     {0x5F, nullptr,                         "Unknown"}, | ||||||
|     {0x60,  NULL,                                       "DebugActiveProcess"}, |     {0x60, nullptr,                         "DebugActiveProcess"}, | ||||||
|     {0x61,  NULL,                                       "BreakDebugProcess"}, |     {0x61, nullptr,                         "BreakDebugProcess"}, | ||||||
|     {0x62,  NULL,                                       "TerminateDebugProcess"}, |     {0x62, nullptr,                         "TerminateDebugProcess"}, | ||||||
|     {0x63,  NULL,                                       "GetProcessDebugEvent"}, |     {0x63, nullptr,                         "GetProcessDebugEvent"}, | ||||||
|     {0x64,  NULL,                                       "ContinueDebugEvent"}, |     {0x64, nullptr,                         "ContinueDebugEvent"}, | ||||||
|     {0x65,  NULL,                                       "GetProcessList"}, |     {0x65, nullptr,                         "GetProcessList"}, | ||||||
|     {0x66,  NULL,                                       "GetThreadList"}, |     {0x66, nullptr,                         "GetThreadList"}, | ||||||
|     {0x67,  NULL,                                       "GetDebugThreadContext"}, |     {0x67, nullptr,                         "GetDebugThreadContext"}, | ||||||
|     {0x68,  NULL,                                       "SetDebugThreadContext"}, |     {0x68, nullptr,                         "SetDebugThreadContext"}, | ||||||
|     {0x69,  NULL,                                       "QueryDebugProcessMemory"}, |     {0x69, nullptr,                         "QueryDebugProcessMemory"}, | ||||||
|     {0x6A,  NULL,                                       "ReadProcessMemory"}, |     {0x6A, nullptr,                         "ReadProcessMemory"}, | ||||||
|     {0x6B,  NULL,                                       "WriteProcessMemory"}, |     {0x6B, nullptr,                         "WriteProcessMemory"}, | ||||||
|     {0x6C,  NULL,                                       "SetHardwareBreakPoint"}, |     {0x6C, nullptr,                         "SetHardwareBreakPoint"}, | ||||||
|     {0x6D,  NULL,                                       "GetDebugThreadParam"}, |     {0x6D, nullptr,                         "GetDebugThreadParam"}, | ||||||
|     {0x6E,  NULL,                                       "Unknown"}, |     {0x6E, nullptr,                         "Unknown"}, | ||||||
|     {0x6F,  NULL,                                       "Unknown"}, |     {0x6F, nullptr,                         "Unknown"}, | ||||||
|     {0x70,  NULL,                                       "ControlProcessMemory"}, |     {0x70, nullptr,                         "ControlProcessMemory"}, | ||||||
|     {0x71,  NULL,                                       "MapProcessMemory"}, |     {0x71, nullptr,                         "MapProcessMemory"}, | ||||||
|     {0x72,  NULL,                                       "UnmapProcessMemory"}, |     {0x72, nullptr,                         "UnmapProcessMemory"}, | ||||||
|     {0x73,  NULL,                                       "Unknown"}, |     {0x73, nullptr,                         "Unknown"}, | ||||||
|     {0x74,  NULL,                                       "Unknown"}, |     {0x74, nullptr,                         "Unknown"}, | ||||||
|     {0x75,  NULL,                                       "Unknown"}, |     {0x75, nullptr,                         "Unknown"}, | ||||||
|     {0x76,  NULL,                                       "TerminateProcess"}, |     {0x76, nullptr,                         "TerminateProcess"}, | ||||||
|     {0x77,  NULL,                                       "Unknown"}, |     {0x77, nullptr,                         "Unknown"}, | ||||||
|     {0x78,  NULL,                                       "CreateResourceLimit"}, |     {0x78, nullptr,                         "CreateResourceLimit"}, | ||||||
|     {0x79,  NULL,                                       "Unknown"}, |     {0x79, nullptr,                         "Unknown"}, | ||||||
|     {0x7A,  NULL,                                       "Unknown"}, |     {0x7A, nullptr,                         "Unknown"}, | ||||||
|     {0x7B,  NULL,                                       "Unknown"}, |     {0x7B, nullptr,                         "Unknown"}, | ||||||
|     {0x7C,  NULL,                                       "KernelSetState"}, |     {0x7C, nullptr,                         "KernelSetState"}, | ||||||
|     {0x7D,  NULL,                                       "QueryProcessMemory"}, |     {0x7D, nullptr,                         "QueryProcessMemory"}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void Register() { | void Register() { | ||||||
|  |  | ||||||
|  | @ -29,6 +29,10 @@ struct ThreadContext { | ||||||
|     u32 fpu_registers[32]; |     u32 fpu_registers[32]; | ||||||
|     u32 fpscr; |     u32 fpscr; | ||||||
|     u32 fpexc; |     u32 fpexc; | ||||||
|  | 
 | ||||||
|  |     // These are not part of native ThreadContext, but needed by emu
 | ||||||
|  |     u32 reg_15; | ||||||
|  |     u32 mode; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum ResetType { | enum ResetType { | ||||||
|  | @ -38,6 +42,15 @@ enum ResetType { | ||||||
|     RESETTYPE_MAX_BIT = (1u << 31), |     RESETTYPE_MAX_BIT = (1u << 31), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum ArbitrationType { | ||||||
|  |     ARBITRATIONTYPE_SIGNAL, | ||||||
|  |     ARBITRATIONTYPE_WAIT_IF_LESS_THAN, | ||||||
|  |     ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN, | ||||||
|  |     ARBITRATIONTYPE_WAIT_IF_LESS_THAN_WITH_TIMEOUT, | ||||||
|  |     ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN_WITH_TIMEOUT, | ||||||
|  |     ARBITRATIONTYPE_MAX_BIT = (1u << 31) | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Namespace SVC
 | // Namespace SVC
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,8 +17,6 @@ namespace GPU { | ||||||
| 
 | 
 | ||||||
| Registers g_regs; | Registers g_regs; | ||||||
| 
 | 
 | ||||||
| static const u32 kFrameTicks = 268123480 / 60;  ///< 268MHz / 60 frames per second
 |  | ||||||
| 
 |  | ||||||
| u64 g_last_ticks = 0; ///< Last CPU ticks
 | u64 g_last_ticks = 0; ///< Last CPU ticks
 | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  |  | ||||||
|  | @ -8,6 +8,9 @@ | ||||||
| 
 | 
 | ||||||
| namespace GPU { | namespace GPU { | ||||||
| 
 | 
 | ||||||
|  | static const u32 kFrameCycles   = 268123480 / 60;   ///< 268MHz / 60 frames per second
 | ||||||
|  | static const u32 kFrameTicks    = kFrameCycles / 3; ///< Approximate number of instructions/frame
 | ||||||
|  | 
 | ||||||
| struct Registers { | struct Registers { | ||||||
|     enum Id : u32 { |     enum Id : u32 { | ||||||
|         FramebufferTopLeft1     = 0x1EF00468,   // Main LCD, first framebuffer for 3D left
 |         FramebufferTopLeft1     = 0x1EF00468,   // Main LCD, first framebuffer for 3D left
 | ||||||
|  |  | ||||||
|  | @ -86,7 +86,7 @@ inline void _Read(T &var, const u32 addr) { | ||||||
|         var = *((const T*)&g_vram[vaddr & VRAM_MASK]); |         var = *((const T*)&g_vram[vaddr & VRAM_MASK]); | ||||||
| 
 | 
 | ||||||
|     } else { |     } else { | ||||||
|         //_assert_msg_(MEMMAP, false, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr);
 |         ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -136,8 +136,7 @@ inline void _Write(u32 addr, const T data) { | ||||||
|      |      | ||||||
|     // Error out...
 |     // Error out...
 | ||||||
|     } else { |     } else { | ||||||
|         _assert_msg_(MEMMAP, false, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, |         ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr); | ||||||
|             data, vaddr); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
| #include "core/system.h" | #include "core/system.h" | ||||||
| #include "core/hw/hw.h" | #include "core/hw/hw.h" | ||||||
| #include "core/hle/hle.h" | #include "core/hle/hle.h" | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
| 
 | 
 | ||||||
| #include "video_core/video_core.h" | #include "video_core/video_core.h" | ||||||
| 
 | 
 | ||||||
|  | @ -26,6 +27,7 @@ void Init(EmuWindow* emu_window) { | ||||||
|     HLE::Init(); |     HLE::Init(); | ||||||
|     CoreTiming::Init(); |     CoreTiming::Init(); | ||||||
|     VideoCore::Init(emu_window); |     VideoCore::Init(emu_window); | ||||||
|  |     Kernel::Init(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RunLoopFor(int cycles) { | void RunLoopFor(int cycles) { | ||||||
|  | @ -42,6 +44,7 @@ void Shutdown() { | ||||||
|     HLE::Shutdown(); |     HLE::Shutdown(); | ||||||
|     CoreTiming::Shutdown(); |     CoreTiming::Shutdown(); | ||||||
|     VideoCore::Shutdown(); |     VideoCore::Shutdown(); | ||||||
|  |     Kernel::Shutdown(); | ||||||
|     g_ctr_file_system.Shutdown(); |     g_ctr_file_system.Shutdown(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue