Seregon/ShadPKG

A tool for deriving PKG packet encryption keys for ps4 written in c++

C++/47.3 KB/No license
ps4MEL/ps4_stubs.cpp
ShadPKG / ps4MEL / ps4_stubs.cpp
1/*
2 * ╔═══════════════════════════════════════════════════════════════════════════╗
3 * ║ PS4 SYSTEM STUBS - IMPLEMENTATION ║
4 * ╠═══════════════════════════════════════════════════════════════════════════╣
5 * ║ Complete mock implementations based on shadPS4 emulator. ║
6 * ║ Reference: https://github.com/shadps4-emu/shadPS4 ║
7 * ╚═══════════════════════════════════════════════════════════════════════════╝
8 */
9 
10#include "ps4_stubs.h"
11#include "sdl_backend.h"
12#include <chrono>
13#include <cstring>
14#include <iostream>
15#include <mutex>
16#include <atomic>
17 
18// ═══════════════════════════════════════════════════════════════════════════
19// LOGGING CONTROL
20// ═══════════════════════════════════════════════════════════════════════════
21 
22#ifndef PS4_STUB_LOG_LEVEL
23#define PS4_STUB_LOG_LEVEL 1 // 0=none, 1=errors, 2=info, 3=debug
24#endif
25 
26#if PS4_STUB_LOG_LEVEL >= 1
27#define LOG_ERROR(name) std::cerr << "[PS4Stub:ERROR] " << name << std::endl
28#else
29#define LOG_ERROR(name)
30#endif
31 
32#if PS4_STUB_LOG_LEVEL >= 2
33#define LOG_INFO(name) std::cout << "[PS4Stub:INFO] " << name << std::endl
34#else
35#define LOG_INFO(name)
36#endif
37 
38#if PS4_STUB_LOG_LEVEL >= 3
39#define LOG_DEBUG(name) std::cout << "[PS4Stub:DEBUG] " << name << std::endl
40#else
41#define LOG_DEBUG(name)
42#endif
43 
44// ═══════════════════════════════════════════════════════════════════════════
45// INDIRECT CALL DISPATCH
46// ═══════════════════════════════════════════════════════════════════════════
47 
48int64_t ps4_indirect_call(void* fn_ptr,
49 int64_t a1, int64_t a2, int64_t a3,
50 int64_t a4, int64_t a5, int64_t a6) {
51 if (!fn_ptr) {
52 LOG_DEBUG("ps4_indirect_call: null fn_ptr, returning 0");
53 return 0;
54 }
55 // All decompiled functions share the same signature: int64_t(int64_t x6)
56 using FnT = int64_t(*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t);
57 return reinterpret_cast<FnT>(fn_ptr)(a1, a2, a3, a4, a5, a6);
58}
59 
60// ═══════════════════════════════════════════════════════════════════════════
61// GLOBAL STATE
62// ═══════════════════════════════════════════════════════════════════════════
63 
64namespace {
65 // PAD state
66 bool g_pad_initialized = false;
67 bool g_pad_opened = false;
68 std::atomic<u64> g_pad_timestamp{0};
69
70 // Audio state
71 bool g_audio_initialized = false;
72 std::atomic<int> g_audio_next_handle{1};
73
74 // Video state
75 bool g_video_initialized = false;
76 std::atomic<int> g_video_next_handle{1};
77 std::atomic<u64> g_flip_count{0};
78 std::atomic<u64> g_vblank_count{0};
79
80 // User state
81 bool g_user_initialized = false;
82 constexpr s32 DEFAULT_USER_ID = 1;
83
84 // Timing
85 auto g_start_time = std::chrono::steady_clock::now();
86
87 u64 GetCurrentTimestamp() {
88 auto now = std::chrono::steady_clock::now();
89 return std::chrono::duration_cast<std::chrono::microseconds>(
90 now - g_start_time).count();
91 }
92}
93 
94extern "C" {
95 
96// ═══════════════════════════════════════════════════════════════════════════
97// PAD (CONTROLLER) - Based on shadPS4 pad.cpp
98// ═══════════════════════════════════════════════════════════════════════════
99 
100s32 scePadInit() {
101 LOG_INFO("scePadInit()");
102 g_pad_initialized = true;
103 return ORBIS_OK;
104}
105 
106s32 scePadOpen(OrbisUserServiceUserId userId, s32 type, s32 index, const OrbisPadOpenParam* pParam) {
107 LOG_INFO("scePadOpen(userId=" << userId << ", type=" << type << ", index=" << index << ")");
108
109 if (!g_pad_initialized) {
110 return -2137653247; // ORBIS_PAD_ERROR_NOT_INITIALIZED
111 }
112 if (userId == -1) {
113 return -2137653244; // ORBIS_PAD_ERROR_DEVICE_NO_HANDLE
114 }
115 if (type != ORBIS_PAD_PORT_TYPE_STANDARD &&
116 type != ORBIS_PAD_PORT_TYPE_SPECIAL &&
117 type != ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL) {
118 return -2137653242; // ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED
119 }
120
121 g_pad_opened = true;
122 return 1; // Return handle 1
123}
124 
125s32 scePadClose(s32 handle) {
126 LOG_DEBUG("scePadClose(handle=" << handle << ")");
127 g_pad_opened = false;
128 return ORBIS_OK;
129}
130 
131s32 scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
132 if (!pData || num <= 0) {
133 return -2137653246; // ORBIS_PAD_ERROR_INVALID_ARG
134 }
135
136 u64 timestamp = GetCurrentTimestamp();
137
138 // Get real input from SDL if available
139 PS4Emu::SDL::PadState sdlPad = {};
140 if (PS4Emu::SDL::IsInitialized()) {
141 sdlPad = PS4Emu::SDL::GetPadState();
142 } else {
143 // Default neutral state
144 sdlPad.connected = true;
145 sdlPad.leftStickX = 128;
146 sdlPad.leftStickY = 128;
147 sdlPad.rightStickX = 128;
148 sdlPad.rightStickY = 128;
149 }
150
151 for (s32 i = 0; i < num; i++) {
152 std::memset(&pData[i], 0, sizeof(OrbisPadData));
153
154 // Use SDL input
155 pData[i].buttons = sdlPad.buttons;
156 pData[i].leftStick.x = sdlPad.leftStickX;
157 pData[i].leftStick.y = sdlPad.leftStickY;
158 pData[i].rightStick.x = sdlPad.rightStickX;
159 pData[i].rightStick.y = sdlPad.rightStickY;
160 pData[i].analogButtons.l2 = sdlPad.l2;
161 pData[i].analogButtons.r2 = sdlPad.r2;
162
163 // Orientation (identity quaternion)
164 pData[i].orientation.x = 0.0f;
165 pData[i].orientation.y = 0.0f;
166 pData[i].orientation.z = 0.0f;
167 pData[i].orientation.w = 1.0f;
168
169 // Acceleration (gravity on Y axis)
170 pData[i].acceleration.x = 0.0f;
171 pData[i].acceleration.y = -1.0f;
172 pData[i].acceleration.z = 0.0f;
173
174 // Angular velocity (stationary)
175 pData[i].angularVelocity.x = 0.0f;
176 pData[i].angularVelocity.y = 0.0f;
177 pData[i].angularVelocity.z = 0.0f;
178
179 // Touch data
180 pData[i].touchData.touchNum = 0;
181
182 // Connection status
183 pData[i].connected = sdlPad.connected;
184 pData[i].connectedCount = 1;
185 pData[i].timestamp = timestamp;
186 pData[i].deviceUniqueDataLen = 0;
187 }
188
189 return num;
190}
191 
192s32 scePadReadState(s32 handle, OrbisPadData* pData) {
193 return scePadRead(handle, pData, 1);
194}
195 
196s32 scePadGetControllerInformation(s32 handle, OrbisPadControllerInformation* pInfo) {
197 LOG_DEBUG("scePadGetControllerInformation(handle=" << handle << ")");
198
199 if (!pInfo) {
200 return -2137653246; // ORBIS_PAD_ERROR_INVALID_ARG
201 }
202
203 std::memset(pInfo, 0, sizeof(OrbisPadControllerInformation));
204
205 pInfo->touchPadInfo.pixelDensity = 1.0f;
206 pInfo->touchPadInfo.resolution.x = 1920;
207 pInfo->touchPadInfo.resolution.y = 950;
208 pInfo->stickInfo.deadZoneLeft = 1;
209 pInfo->stickInfo.deadZoneRight = 1;
210 pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD;
211 pInfo->connectedCount = 1;
212 pInfo->connected = (handle >= 0);
213 pInfo->deviceClass = OrbisPadDeviceClass::Standard;
214
215 return ORBIS_OK;
216}
217 
218s32 scePadSetVibration(s32 handle, const OrbisPadVibrationParam* pParam) {
219 LOG_DEBUG("scePadSetVibration(handle=" << handle << ")");
220 return ORBIS_OK;
221}
222 
223s32 scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pParam) {
224 LOG_DEBUG("scePadSetLightBar(handle=" << handle << ")");
225 return ORBIS_OK;
226}
227 
228s32 scePadResetLightBar(s32 handle) {
229 LOG_DEBUG("scePadResetLightBar(handle=" << handle << ")");
230 return ORBIS_OK;
231}
232 
233s32 scePadResetOrientation(s32 handle) {
234 LOG_DEBUG("scePadResetOrientation(handle=" << handle << ")");
235 return ORBIS_OK;
236}
237 
238s32 scePadSetMotionSensorState(s32 handle, bool bEnable) {
239 LOG_DEBUG("scePadSetMotionSensorState(handle=" << handle << ", enable=" << bEnable << ")");
240 return ORBIS_OK;
241}
242 
243s32 scePadGetHandle(OrbisUserServiceUserId userId, s32 type, s32 index) {
244 if (!g_pad_initialized) {
245 return -2137653247;
246 }
247 if (userId == -1 || !g_pad_opened) {
248 return -2137653244;
249 }
250 return 1;
251}
252 
253// ═══════════════════════════════════════════════════════════════════════════
254// AUDIO OUT - Based on shadPS4 audioout.cpp
255// ═══════════════════════════════════════════════════════════════════════════
256 
257s32 sceAudioOutInit() {
258 LOG_INFO("sceAudioOutInit()");
259 if (g_audio_initialized) {
260 return -2144993279; // ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT
261 }
262 g_audio_initialized = true;
263 return ORBIS_OK;
264}
265 
266s32 sceAudioOutOpen(OrbisUserServiceUserId userId, s32 portType, s32 index,
267 u32 length, u32 sampleRate, u32 paramType) {
268 LOG_INFO("sceAudioOutOpen(userId=" << userId << ", portType=" << portType <<
269 ", length=" << length << ", sampleRate=" << sampleRate << ")");
270
271 if (!g_audio_initialized) {
272 return -2144993280; // ORBIS_AUDIO_OUT_ERROR_NOT_INIT
273 }
274 if (sampleRate != 48000) {
275 return -2144993274; // ORBIS_AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ
276 }
277
278 return g_audio_next_handle++;
279}
280 
281s32 sceAudioOutClose(s32 handle) {
282 LOG_DEBUG("sceAudioOutClose(handle=" << handle << ")");
283 return ORBIS_OK;
284}
285 
286s32 sceAudioOutOutput(s32 handle, void* ptr) {
287 // Pretend we output the audio immediately
288 // This is called every frame, so we don't log it
289 return 256; // Return samples sent
290}
291 
292s32 sceAudioOutOutputs(void* param, u32 num) {
293 // Process multiple audio outputs
294 return ORBIS_OK;
295}
296 
297s32 sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
298 LOG_DEBUG("sceAudioOutSetVolume(handle=" << handle << ")");
299 return ORBIS_OK;
300}
301 
302s32 sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state) {
303 if (!state) {
304 return -2144993277; // ORBIS_AUDIO_OUT_ERROR_INVALID_POINTER
305 }
306
307 std::memset(state, 0, sizeof(OrbisAudioOutPortState));
308 state->output = 1;
309 state->channel = 2;
310 state->volume = static_cast<s16>(SCE_AUDIO_OUT_VOLUME_0DB);
311
312 return ORBIS_OK;
313}
314 
315s32 sceAudioOutGetLastOutputTime(s32 handle, u64* outputTime) {
316 if (!outputTime) {
317 return -2144993277;
318 }
319 *outputTime = GetCurrentTimestamp();
320 return ORBIS_OK;
321}
322 
323// ═══════════════════════════════════════════════════════════════════════════
324// VIDEO OUT - Based on shadPS4 video_out.cpp
325// ═══════════════════════════════════════════════════════════════════════════
326 
327s32 sceVideoOutOpen(OrbisUserServiceUserId userId, s32 busType, s32 index, const void* param) {
328 LOG_INFO("sceVideoOutOpen(userId=" << userId << ", busType=" << busType << ")");
329
330 if (busType != SCE_VIDEO_OUT_BUS_TYPE_MAIN) {
331 return -2144796671; // ORBIS_VIDEO_OUT_ERROR_INVALID_VALUE
332 }
333 if (index != 0) {
334 return -2144796671;
335 }
336
337 // Initialize SDL window
338 if (!PS4Emu::SDL::IsInitialized()) {
339 if (!PS4Emu::SDL::Initialize("PS4 Game", 1280, 720)) {
340 std::cerr << "[VideoOut] Failed to initialize SDL window" << std::endl;
341 }
342 }
343
344 g_video_initialized = true;
345 return g_video_next_handle++;
346}
347 
348s32 sceVideoOutClose(s32 handle) {
349 LOG_DEBUG("sceVideoOutClose(handle=" << handle << ")");
350
351 // Shutdown SDL when video is closed
352 if (PS4Emu::SDL::IsInitialized()) {
353 PS4Emu::SDL::Shutdown();
354 }
355
356 return ORBIS_OK;
357}
358 
359void sceVideoOutSetBufferAttribute(BufferAttribute* attribute, u32 pixelFormat,
360 u32 tilingMode, u32 aspectRatio, u32 width,
361 u32 height, u32 pitchInPixel) {
362 LOG_INFO("sceVideoOutSetBufferAttribute(width=" << width << ", height=" << height << ")");
363
364 if (attribute) {
365 std::memset(attribute, 0, sizeof(BufferAttribute));
366 attribute->pixel_format = static_cast<PixelFormat>(pixelFormat);
367 attribute->tiling_mode = static_cast<TilingMode>(tilingMode);
368 attribute->aspect_ratio = aspectRatio;
369 attribute->width = width;
370 attribute->height = height;
371 attribute->pitch_in_pixel = pitchInPixel;
372 }
373}
374 
375s32 sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,
376 s32 bufferNum, const BufferAttribute* attribute) {
377 LOG_INFO("sceVideoOutRegisterBuffers(handle=" << handle << ", bufferNum=" << bufferNum << ")");
378
379 if (!addresses || !attribute) {
380 return -2144796666; // ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS
381 }
382
383 return ORBIS_OK;
384}
385 
386s32 sceVideoOutUnregisterBuffers(s32 handle, s32 attributeIndex) {
387 LOG_DEBUG("sceVideoOutUnregisterBuffers(handle=" << handle << ")");
388 return ORBIS_OK;
389}
390 
391s32 sceVideoOutSetFlipRate(s32 handle, s32 rate) {
392 LOG_DEBUG("sceVideoOutSetFlipRate(handle=" << handle << ", rate=" << rate << ")");
393 return ORBIS_OK;
394}
395 
396s32 sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode, s64 flipArg) {
397 // This is called every frame - increment flip count
398 g_flip_count++;
399
400 // If SDL is initialized, present the frame
401 if (PS4Emu::SDL::IsInitialized()) {
402 // Poll events (input)
403 PS4Emu::SDL::PollEvents();
404
405 // Clear screen with a color based on frame count (visual feedback)
406 uint64_t frame = g_flip_count.load();
407 uint8_t r = static_cast<uint8_t>((frame * 2) % 64 + 32); // Dark blue-ish
408 uint8_t g = static_cast<uint8_t>((frame) % 64 + 32);
409 uint8_t b = static_cast<uint8_t>(128 + (frame % 64)); // Blue dominant
410 PS4Emu::SDL::ClearScreen(r, g, b);
411
412 // Present the frame (with VSync)
413 PS4Emu::SDL::Present();
414 }
415
416 return ORBIS_OK;
417}
418 
419s32 sceVideoOutGetFlipStatus(s32 handle, FlipStatus* status) {
420 if (!status) {
421 return -2144796666;
422 }
423
424 std::memset(status, 0, sizeof(FlipStatus));
425 status->count = g_flip_count.load();
426 status->process_time = GetCurrentTimestamp();
427 status->tsc = GetCurrentTimestamp();
428 status->flip_arg = 0;
429 status->submit_tsc = GetCurrentTimestamp();
430 status->gc_queue_num = 0;
431 status->flip_pending_num = 0;
432 status->current_buffer = 0;
433
434 return ORBIS_OK;
435}
436 
437s32 sceVideoOutGetVblankStatus(s32 handle, SceVideoOutVblankStatus* status) {
438 if (!status) {
439 return -2144796666;
440 }
441
442 g_vblank_count++;
443
444 std::memset(status, 0, sizeof(SceVideoOutVblankStatus));
445 status->count = g_vblank_count.load();
446 status->process_time = GetCurrentTimestamp();
447 status->tsc = GetCurrentTimestamp();
448
449 return ORBIS_OK;
450}
451 
452s32 sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status) {
453 LOG_DEBUG("sceVideoOutGetResolutionStatus(handle=" << handle << ")");
454
455 if (!status) {
456 return -2144796666;
457 }
458
459 std::memset(status, 0, sizeof(SceVideoOutResolutionStatus));
460 status->width = 1920;
461 status->height = 1080;
462 status->paneWidth = 1920;
463 status->paneHeight = 1080;
464 status->refreshRate = 60000000; // 60 Hz in microhertz
465 status->screenSize = 0.0f;
466
467 return ORBIS_OK;
468}
469 
470s32 sceVideoOutIsFlipPending(s32 handle) {
471 return 0; // No flips pending
472}
473 
474s32 sceVideoOutWaitVblank(s32 handle) {
475 // Simulate waiting for vblank (~16.67ms at 60Hz)
476 // In a real implementation, this would sync with the display
477 return ORBIS_OK;
478}
479 
480s32 sceVideoOutGetDeviceCapabilityInfo(s32 handle, SceVideoOutDeviceCapabilityInfo* info) {
481 if (info) {
482 info->capability = 0;
483 }
484 return ORBIS_OK;
485}
486 
487s32 sceVideoOutColorSettingsSetGamma(SceVideoOutColorSettings* settings, float gamma) {
488 if (gamma < 0.1f || gamma > 2.0f) {
489 return -2144796671;
490 }
491 if (settings) {
492 settings->gamma = gamma;
493 }
494 return ORBIS_OK;
495}
496 
497s32 sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettings* settings) {
498 return ORBIS_OK;
499}
500 
501// ═══════════════════════════════════════════════════════════════════════════
502// GNM (GRAPHICS) - GPU command submission stubs
503// ═══════════════════════════════════════════════════════════════════════════
504 
505s32 sceGnmSubmitCommandBuffers(u32 count, void** dcbGpuAddrs, u32* dcbSizesInBytes,
506 void** ccbGpuAddrs, u32* ccbSizesInBytes) {
507 static u64 gnm_call_count = 0;
508 gnm_call_count++;
509
510 // Log every 60 calls (roughly once per second at 60fps)
511 if (gnm_call_count % 60 == 1) {
512 std::cout << "[GNM] SubmitCommandBuffers #" << gnm_call_count
513 << " count=" << count;
514 if (dcbSizesInBytes && count > 0) {
515 std::cout << " dcbSize=" << dcbSizesInBytes[0];
516 }
517 std::cout << std::endl;
518 }
519
520 return ORBIS_OK;
521}
522 
523s32 sceGnmSubmitAndFlipCommandBuffers(u32 count, void** dcbGpuAddrs, u32* dcbSizesInBytes,
524 void** ccbGpuAddrs, u32* ccbSizesInBytes,
525 s32 videoHandle, s32 bufferIndex,
526 s32 flipMode, s64 flipArg) {
527 g_flip_count++;
528 return ORBIS_OK;
529}
530 
531u32 sceGnmGetGpuCoreClockFrequency() {
532 return 800000000; // 800 MHz
533}
534 
535s32 sceGnmFlushGarlic() {
536 return ORBIS_OK;
537}
538 
539// ═══════════════════════════════════════════════════════════════════════════
540// USER SERVICE - Based on shadPS4 userservice.cpp
541// ═══════════════════════════════════════════════════════════════════════════
542 
543s32 sceUserServiceInitialize(void* params) {
544 LOG_INFO("sceUserServiceInitialize()");
545 g_user_initialized = true;
546 return ORBIS_OK;
547}
548 
549s32 sceUserServiceTerminate() {
550 g_user_initialized = false;
551 return ORBIS_OK;
552}
553 
554s32 sceUserServiceGetInitialUser(OrbisUserServiceUserId* userId) {
555 if (userId) {
556 *userId = DEFAULT_USER_ID;
557 }
558 return ORBIS_OK;
559}
560 
561s32 sceUserServiceGetLoginUserIdList(OrbisUserServiceUserId* userIdList) {
562 if (userIdList) {
563 userIdList[0] = DEFAULT_USER_ID;
564 userIdList[1] = -1;
565 userIdList[2] = -1;
566 userIdList[3] = -1;
567 }
568 return ORBIS_OK;
569}
570 
571s32 sceUserServiceGetUserName(OrbisUserServiceUserId userId, char* userName, size_t size) {
572 if (userName && size > 0) {
573 strncpy(userName, "Player", size - 1);
574 userName[size - 1] = '\0';
575 }
576 return ORBIS_OK;
577}
578 
579// ═══════════════════════════════════════════════════════════════════════════
580// SYSTEM SERVICE
581// ═══════════════════════════════════════════════════════════════════════════
582 
583s32 sceSystemServiceHideSplashScreen() {
584 LOG_INFO("sceSystemServiceHideSplashScreen()");
585 return ORBIS_OK;
586}
587 
588s32 sceSystemServiceParamGetInt(s32 paramId, s32* value) {
589 if (value) {
590 *value = 0;
591 }
592 return ORBIS_OK;
593}
594 
595s32 sceSystemServiceParamGetString(s32 paramId, char* buf, size_t bufSize) {
596 if (buf && bufSize > 0) {
597 buf[0] = '\0';
598 }
599 return ORBIS_OK;
600}
601 
602s32 sceSystemServiceGetStatus(void* status) {
603 return ORBIS_OK;
604}
605 
606// ═══════════════════════════════════════════════════════════════════════════
607// SAVE DATA
608// ═══════════════════════════════════════════════════════════════════════════
609 
610s32 sceSaveDataInitialize3(void* params) {
611 LOG_INFO("sceSaveDataInitialize3()");
612 return ORBIS_OK;
613}
614 
615s32 sceSaveDataMount(void* mount) {
616 return ORBIS_OK;
617}
618 
619s32 sceSaveDataUmount(void* umount) {
620 return ORBIS_OK;
621}
622 
623s32 sceSaveDataDirNameSearch(void* search) {
624 return ORBIS_OK;
625}
626 
627// ═══════════════════════════════════════════════════════════════════════════
628// COMMON DIALOG
629// ═══════════════════════════════════════════════════════════════════════════
630 
631s32 sceCommonDialogInitialize() {
632 LOG_INFO("sceCommonDialogInitialize()");
633 return ORBIS_OK;
634}
635 
636s32 sceMsgDialogInitialize() {
637 LOG_INFO("sceMsgDialogInitialize()");
638 return ORBIS_OK;
639}
640 
641s32 sceMsgDialogOpen(void* param) {
642 LOG_INFO("sceMsgDialogOpen(param=" << param << ")");
643 return ORBIS_OK;
644}
645 
646s32 sceMsgDialogUpdateStatus() {
647 LOG_DEBUG("sceMsgDialogUpdateStatus() -> FINISHED");
648 return 4; // FINISHED
649}
650 
651s32 sceMsgDialogTerminate() {
652 LOG_INFO("sceMsgDialogTerminate()");
653 return ORBIS_OK;
654}
655 
656s32 sceMsgDialogGetResult(void* result) {
657 LOG_INFO("sceMsgDialogGetResult(result=" << result << ")");
658 return ORBIS_OK;
659}
660 
661// ═══════════════════════════════════════════════════════════════════════════
662// NETWORK (NP)
663// ═══════════════════════════════════════════════════════════════════════════
664 
665s32 sceNpSetNpTitleId(void* titleId, void* titleSecret) {
666 return ORBIS_OK;
667}
668 
669s32 sceNpCheckCallback() {
670 return ORBIS_OK;
671}
672 
673s32 sceNetInit() {
674 return ORBIS_OK;
675}
676 
677s32 sceNetCtlInit() {
678 return ORBIS_OK;
679}
680 
681s32 sceNetCtlTerm() {
682 return ORBIS_OK;
683}
684 
685s32 sceNetCtlGetInfo(s32 code, void* info) {
686 return ORBIS_OK;
687}
688 
689// ═══════════════════════════════════════════════════════════════════════════
690// IME (INPUT METHOD)
691// ═══════════════════════════════════════════════════════════════════════════
692 
693s32 sceImeDialogInit(void* param, void* extended) {
694 return ORBIS_OK;
695}
696 
697s32 sceImeDialogGetStatus() {
698 return 0; // Not active
699}
700 
701s32 sceImeDialogTerm() {
702 return ORBIS_OK;
703}
704 
705// ═══════════════════════════════════════════════════════════════════════════
706// SYSMODULE
707// ═══════════════════════════════════════════════════════════════════════════
708 
709s32 sceSysmoduleLoadModule(s32 id) {
710 LOG_INFO("sceSysmoduleLoadModule(id=" << id << ")");
711 return ORBIS_OK;
712}
713 
714s32 sceSysmoduleUnloadModule(s32 id) {
715 return ORBIS_OK;
716}
717 
718s32 sceSysmoduleIsLoaded(s32 id) {
719 return ORBIS_OK; // Module is loaded
720}
721 
722} // extern "C"
723