diff options
Diffstat (limited to 'src/core/hle/svc.cpp')
| -rw-r--r-- | src/core/hle/svc.cpp | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp new file mode 100644 index 000000000..90c05cb74 --- /dev/null +++ b/src/core/hle/svc.cpp | |||
| @@ -0,0 +1,362 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <map> | ||
| 6 | #include <string> | ||
| 7 | |||
| 8 | #include "common/symbols.h" | ||
| 9 | |||
| 10 | #include "core/mem_map.h" | ||
| 11 | |||
| 12 | #include "core/hle/kernel/kernel.h" | ||
| 13 | #include "core/hle/kernel/mutex.h" | ||
| 14 | #include "core/hle/kernel/thread.h" | ||
| 15 | |||
| 16 | #include "core/hle/function_wrappers.h" | ||
| 17 | #include "core/hle/svc.h" | ||
| 18 | #include "core/hle/service/service.h" | ||
| 19 | #include "core/hle/kernel/thread.h" | ||
| 20 | |||
| 21 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 22 | // Namespace SVC | ||
| 23 | |||
| 24 | namespace SVC { | ||
| 25 | |||
| 26 | enum ControlMemoryOperation { | ||
| 27 | MEMORY_OPERATION_HEAP = 0x00000003, | ||
| 28 | MEMORY_OPERATION_GSP_HEAP = 0x00010003, | ||
| 29 | }; | ||
| 30 | |||
| 31 | enum MapMemoryPermission { | ||
| 32 | MEMORY_PERMISSION_UNMAP = 0x00000000, | ||
| 33 | MEMORY_PERMISSION_NORMAL = 0x00000001, | ||
| 34 | }; | ||
| 35 | |||
| 36 | /// Map application or GSP heap memory | ||
| 37 | Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | ||
| 38 | u32* outaddr = (u32*)_outaddr; | ||
| 39 | u32 virtual_address = 0x00000000; | ||
| 40 | |||
| 41 | DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", | ||
| 42 | operation, addr0, addr1, size, permissions); | ||
| 43 | |||
| 44 | switch (operation) { | ||
| 45 | |||
| 46 | // Map normal heap memory | ||
| 47 | case MEMORY_OPERATION_HEAP: | ||
| 48 | virtual_address = Memory::MapBlock_Heap(size, operation, permissions); | ||
| 49 | break; | ||
| 50 | |||
| 51 | // Map GSP heap memory | ||
| 52 | case MEMORY_OPERATION_GSP_HEAP: | ||
| 53 | virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions); | ||
| 54 | break; | ||
| 55 | |||
| 56 | // Unknown ControlMemory operation | ||
| 57 | default: | ||
| 58 | ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); | ||
| 59 | } | ||
| 60 | if (NULL != outaddr) { | ||
| 61 | *outaddr = virtual_address; | ||
| 62 | } | ||
| 63 | Core::g_app_core->SetReg(1, virtual_address); | ||
| 64 | |||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Maps a memory block to specified address | ||
| 69 | Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { | ||
| 70 | DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", | ||
| 71 | memblock, addr, mypermissions, otherpermission); | ||
| 72 | switch (mypermissions) { | ||
| 73 | case MEMORY_PERMISSION_NORMAL: | ||
| 74 | case MEMORY_PERMISSION_NORMAL + 1: | ||
| 75 | case MEMORY_PERMISSION_NORMAL + 2: | ||
| 76 | Memory::MapBlock_Shared(memblock, addr, mypermissions); | ||
| 77 | break; | ||
| 78 | default: | ||
| 79 | ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); | ||
| 80 | } | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Connect to an OS service given the port name, returns the handle to the port to out | ||
| 85 | Result ConnectToPort(void* out, const char* port_name) { | ||
| 86 | Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); | ||
| 87 | if (service) { | ||
| 88 | Core::g_app_core->SetReg(1, service->GetHandle()); | ||
| 89 | } else { | ||
| 90 | PanicYesNo("ConnectToPort called port_name=%s, but it is not implemented!", port_name); | ||
| 91 | } | ||
| 92 | DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); | ||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | /// Synchronize to an OS service | ||
| 97 | Result SendSyncRequest(Handle handle) { | ||
| 98 | DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X"); | ||
| 99 | Service::Interface* service = Service::g_manager->FetchFromHandle(handle); | ||
| 100 | service->Sync(); | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Close a handle | ||
| 105 | Result CloseHandle(Handle handle) { | ||
| 106 | // ImplementMe | ||
| 107 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); | ||
| 108 | return 0; | ||
| 109 | } | ||
| 110 | |||
| 111 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds | ||
| 112 | Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | ||
| 113 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", | ||
| 114 | handle, nano_seconds); | ||
| 115 | Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | ||
| 120 | Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) { | ||
| 121 | s32* out = (s32*)_out; | ||
| 122 | Handle* handles = (Handle*)_handles; | ||
| 123 | |||
| 124 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s", | ||
| 125 | handle_count, (wait_all ? "true" : "false"), nano_seconds); | ||
| 126 | |||
| 127 | for (u32 i = 0; i < handle_count; i++) { | ||
| 128 | DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); | ||
| 129 | } | ||
| 130 | Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Create an address arbiter (to allocate access to shared resources) | ||
| 135 | Result CreateAddressArbiter(void* arbiter) { | ||
| 136 | // ImplementMe | ||
| 137 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called"); | ||
| 138 | Core::g_app_core->SetReg(1, 0xFABBDADD); | ||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit | ||
| 143 | void OutputDebugString(const char* string) { | ||
| 144 | NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string); | ||
| 145 | } | ||
| 146 | |||
| 147 | /// Get resource limit | ||
| 148 | Result GetResourceLimit(void* resource_limit, Handle process) { | ||
| 149 | // With regards to proceess values: | ||
| 150 | // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for | ||
| 151 | // the current KThread. | ||
| 152 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); | ||
| 153 | Core::g_app_core->SetReg(1, 0xDEADBEEF); | ||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | /// Get resource limit current values | ||
| 158 | Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { | ||
| 159 | //s64* values = (s64*)_values; | ||
| 160 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", | ||
| 161 | resource_limit, names, name_count); | ||
| 162 | Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now | ||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | /// Creates a new thread | ||
| 167 | Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { | ||
| 168 | std::string name; | ||
| 169 | if (Symbols::HasSymbol(entry_point)) { | ||
| 170 | TSymbol symbol = Symbols::GetSymbol(entry_point); | ||
| 171 | name = symbol.name; | ||
| 172 | } else { | ||
| 173 | char buff[100]; | ||
| 174 | sprintf(buff, "%s", "unknown-%08X", entry_point); | ||
| 175 | name = buff; | ||
| 176 | } | ||
| 177 | |||
| 178 | Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id, | ||
| 179 | stack_top); | ||
| 180 | |||
| 181 | Core::g_app_core->SetReg(1, thread); | ||
| 182 | |||
| 183 | DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " | ||
| 184 | "threadpriority=0x%08X, processorid=0x%08X : created handle 0x%08X", entry_point, | ||
| 185 | name.c_str(), arg, stack_top, priority, processor_id, thread); | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | /// Create a mutex | ||
| 191 | Result CreateMutex(void* _mutex, u32 initial_locked) { | ||
| 192 | Handle* mutex = (Handle*)_mutex; | ||
| 193 | *mutex = Kernel::CreateMutex((initial_locked != 0)); | ||
| 194 | Core::g_app_core->SetReg(1, *mutex); | ||
| 195 | DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s : created handle 0x%08X", | ||
| 196 | initial_locked ? "true" : "false", *mutex); | ||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | /// Release a mutex | ||
| 201 | Result ReleaseMutex(Handle handle) { | ||
| 202 | DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle); | ||
| 203 | Kernel::ReleaseMutex(handle); | ||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | |||
| 207 | /// Get current thread ID | ||
| 208 | Result GetThreadId(void* thread_id, u32 thread) { | ||
| 209 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread); | ||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | /// Query memory | ||
| 214 | Result QueryMemory(void *_info, void *_out, u32 addr) { | ||
| 215 | MemoryInfo* info = (MemoryInfo*) _info; | ||
| 216 | PageInfo* out = (PageInfo*) _out; | ||
| 217 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr); | ||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | /// Create an event | ||
| 222 | Result CreateEvent(void* _event, u32 reset_type) { | ||
| 223 | Handle* event = (Handle*)_event; | ||
| 224 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type); | ||
| 225 | Core::g_app_core->SetReg(1, 0xBADC0DE0); | ||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | const HLE::FunctionDef SVC_Table[] = { | ||
| 230 | {0x00, NULL, "Unknown"}, | ||
| 231 | {0x01, WrapI_VUUUUU<ControlMemory>, "ControlMemory"}, | ||
| 232 | {0x02, WrapI_VVU<QueryMemory>, "QueryMemory"}, | ||
| 233 | {0x03, NULL, "ExitProcess"}, | ||
| 234 | {0x04, NULL, "GetProcessAffinityMask"}, | ||
| 235 | {0x05, NULL, "SetProcessAffinityMask"}, | ||
| 236 | {0x06, NULL, "GetProcessIdealProcessor"}, | ||
| 237 | {0x07, NULL, "SetProcessIdealProcessor"}, | ||
| 238 | {0x08, WrapI_UUUUU<CreateThread>, "CreateThread"}, | ||
| 239 | {0x09, NULL, "ExitThread"}, | ||
| 240 | {0x0A, NULL, "SleepThread"}, | ||
| 241 | {0x0B, NULL, "GetThreadPriority"}, | ||
| 242 | {0x0C, NULL, "SetThreadPriority"}, | ||
| 243 | {0x0D, NULL, "GetThreadAffinityMask"}, | ||
| 244 | {0x0E, NULL, "SetThreadAffinityMask"}, | ||
| 245 | {0x0F, NULL, "GetThreadIdealProcessor"}, | ||
| 246 | {0x10, NULL, "SetThreadIdealProcessor"}, | ||
| 247 | {0x11, NULL, "GetCurrentProcessorNumber"}, | ||
| 248 | {0x12, NULL, "Run"}, | ||
| 249 | {0x13, WrapI_VU<CreateMutex>, "CreateMutex"}, | ||
| 250 | {0x14, WrapI_U<ReleaseMutex>, "ReleaseMutex"}, | ||
| 251 | {0x15, NULL, "CreateSemaphore"}, | ||
| 252 | {0x16, NULL, "ReleaseSemaphore"}, | ||
| 253 | {0x17, WrapI_VU<CreateEvent>, "CreateEvent"}, | ||
| 254 | {0x18, NULL, "SignalEvent"}, | ||
| 255 | {0x19, NULL, "ClearEvent"}, | ||
| 256 | {0x1A, NULL, "CreateTimer"}, | ||
| 257 | {0x1B, NULL, "SetTimer"}, | ||
| 258 | {0x1C, NULL, "CancelTimer"}, | ||
| 259 | {0x1D, NULL, "ClearTimer"}, | ||
| 260 | {0x1E, NULL, "CreateMemoryBlock"}, | ||
| 261 | {0x1F, WrapI_UUUU<MapMemoryBlock>, "MapMemoryBlock"}, | ||
| 262 | {0x20, NULL, "UnmapMemoryBlock"}, | ||
| 263 | {0x21, WrapI_V<CreateAddressArbiter>, "CreateAddressArbiter"}, | ||
| 264 | {0x22, NULL, "ArbitrateAddress"}, | ||
| 265 | {0x23, WrapI_U<CloseHandle>, "CloseHandle"}, | ||
| 266 | {0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"}, | ||
| 267 | {0x25, WrapI_VVUUS64<WaitSynchronizationN>, "WaitSynchronizationN"}, | ||
| 268 | {0x26, NULL, "SignalAndWait"}, | ||
| 269 | {0x27, NULL, "DuplicateHandle"}, | ||
| 270 | {0x28, NULL, "GetSystemTick"}, | ||
| 271 | {0x29, NULL, "GetHandleInfo"}, | ||
| 272 | {0x2A, NULL, "GetSystemInfo"}, | ||
| 273 | {0x2B, NULL, "GetProcessInfo"}, | ||
| 274 | {0x2C, NULL, "GetThreadInfo"}, | ||
| 275 | {0x2D, WrapI_VC<ConnectToPort>, "ConnectToPort"}, | ||
| 276 | {0x2E, NULL, "SendSyncRequest1"}, | ||
| 277 | {0x2F, NULL, "SendSyncRequest2"}, | ||
| 278 | {0x30, NULL, "SendSyncRequest3"}, | ||
| 279 | {0x31, NULL, "SendSyncRequest4"}, | ||
| 280 | {0x32, WrapI_U<SendSyncRequest>, "SendSyncRequest"}, | ||
| 281 | {0x33, NULL, "OpenProcess"}, | ||
| 282 | {0x34, NULL, "OpenThread"}, | ||
| 283 | {0x35, NULL, "GetProcessId"}, | ||
| 284 | {0x36, NULL, "GetProcessIdOfThread"}, | ||
| 285 | {0x37, WrapI_VU<GetThreadId>, "GetThreadId"}, | ||
| 286 | {0x38, WrapI_VU<GetResourceLimit>, "GetResourceLimit"}, | ||
| 287 | {0x39, NULL, "GetResourceLimitLimitValues"}, | ||
| 288 | {0x3A, WrapI_VUVI<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, | ||
| 289 | {0x3B, NULL, "GetThreadContext"}, | ||
| 290 | {0x3C, NULL, "Break"}, | ||
| 291 | {0x3D, WrapV_C<OutputDebugString>, "OutputDebugString"}, | ||
| 292 | {0x3E, NULL, "ControlPerformanceCounter"}, | ||
| 293 | {0x3F, NULL, "Unknown"}, | ||
| 294 | {0x40, NULL, "Unknown"}, | ||
| 295 | {0x41, NULL, "Unknown"}, | ||
| 296 | {0x42, NULL, "Unknown"}, | ||
| 297 | {0x43, NULL, "Unknown"}, | ||
| 298 | {0x44, NULL, "Unknown"}, | ||
| 299 | {0x45, NULL, "Unknown"}, | ||
| 300 | {0x46, NULL, "Unknown"}, | ||
| 301 | {0x47, NULL, "CreatePort"}, | ||
| 302 | {0x48, NULL, "CreateSessionToPort"}, | ||
| 303 | {0x49, NULL, "CreateSession"}, | ||
| 304 | {0x4A, NULL, "AcceptSession"}, | ||
| 305 | {0x4B, NULL, "ReplyAndReceive1"}, | ||
| 306 | {0x4C, NULL, "ReplyAndReceive2"}, | ||
| 307 | {0x4D, NULL, "ReplyAndReceive3"}, | ||
| 308 | {0x4E, NULL, "ReplyAndReceive4"}, | ||
| 309 | {0x4F, NULL, "ReplyAndReceive"}, | ||
| 310 | {0x50, NULL, "BindInterrupt"}, | ||
| 311 | {0x51, NULL, "UnbindInterrupt"}, | ||
| 312 | {0x52, NULL, "InvalidateProcessDataCache"}, | ||
| 313 | {0x53, NULL, "StoreProcessDataCache"}, | ||
| 314 | {0x54, NULL, "FlushProcessDataCache"}, | ||
| 315 | {0x55, NULL, "StartInterProcessDma"}, | ||
| 316 | {0x56, NULL, "StopDma"}, | ||
| 317 | {0x57, NULL, "GetDmaState"}, | ||
| 318 | {0x58, NULL, "RestartDma"}, | ||
| 319 | {0x59, NULL, "Unknown"}, | ||
| 320 | {0x5A, NULL, "Unknown"}, | ||
| 321 | {0x5B, NULL, "Unknown"}, | ||
| 322 | {0x5C, NULL, "Unknown"}, | ||
| 323 | {0x5D, NULL, "Unknown"}, | ||
| 324 | {0x5E, NULL, "Unknown"}, | ||
| 325 | {0x5F, NULL, "Unknown"}, | ||
| 326 | {0x60, NULL, "DebugActiveProcess"}, | ||
| 327 | {0x61, NULL, "BreakDebugProcess"}, | ||
| 328 | {0x62, NULL, "TerminateDebugProcess"}, | ||
| 329 | {0x63, NULL, "GetProcessDebugEvent"}, | ||
| 330 | {0x64, NULL, "ContinueDebugEvent"}, | ||
| 331 | {0x65, NULL, "GetProcessList"}, | ||
| 332 | {0x66, NULL, "GetThreadList"}, | ||
| 333 | {0x67, NULL, "GetDebugThreadContext"}, | ||
| 334 | {0x68, NULL, "SetDebugThreadContext"}, | ||
| 335 | {0x69, NULL, "QueryDebugProcessMemory"}, | ||
| 336 | {0x6A, NULL, "ReadProcessMemory"}, | ||
| 337 | {0x6B, NULL, "WriteProcessMemory"}, | ||
| 338 | {0x6C, NULL, "SetHardwareBreakPoint"}, | ||
| 339 | {0x6D, NULL, "GetDebugThreadParam"}, | ||
| 340 | {0x6E, NULL, "Unknown"}, | ||
| 341 | {0x6F, NULL, "Unknown"}, | ||
| 342 | {0x70, NULL, "ControlProcessMemory"}, | ||
| 343 | {0x71, NULL, "MapProcessMemory"}, | ||
| 344 | {0x72, NULL, "UnmapProcessMemory"}, | ||
| 345 | {0x73, NULL, "Unknown"}, | ||
| 346 | {0x74, NULL, "Unknown"}, | ||
| 347 | {0x75, NULL, "Unknown"}, | ||
| 348 | {0x76, NULL, "TerminateProcess"}, | ||
| 349 | {0x77, NULL, "Unknown"}, | ||
| 350 | {0x78, NULL, "CreateResourceLimit"}, | ||
| 351 | {0x79, NULL, "Unknown"}, | ||
| 352 | {0x7A, NULL, "Unknown"}, | ||
| 353 | {0x7B, NULL, "Unknown"}, | ||
| 354 | {0x7C, NULL, "KernelSetState"}, | ||
| 355 | {0x7D, NULL, "QueryProcessMemory"}, | ||
| 356 | }; | ||
| 357 | |||
| 358 | void Register() { | ||
| 359 | HLE::RegisterModule("SVC_Table", ARRAY_SIZE(SVC_Table), SVC_Table); | ||
| 360 | } | ||
| 361 | |||
| 362 | } // namespace | ||