Seregon/ShadPKG

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

C++/47.3 KB/No license
ps4MEL/ps4_pthread.cpp
ShadPKG / ps4MEL / ps4_pthread.cpp
1/*
2 * ╔═══════════════════════════════════════════════════════════════════════════╗
3 * ║ PS4 PTHREAD STUBS - IMPLEMENTATION ║
4 * ╠═══════════════════════════════════════════════════════════════════════════╣
5 * ║ Real pthread wrappers for PS4 threading primitives. ║
6 * ╚═══════════════════════════════════════════════════════════════════════════╝
7 */
8 
9#include "ps4_pthread.h"
10#include "ps4_kernel.h"
11#include "ps4_tls.h"
12#include <condition_variable>
13#include <cstring>
14#include <iostream>
15#include <map>
16#include <mutex>
17#include <shared_mutex>
18#include <thread>
19 
20/*
21 * ┌─────────────────────────────────────────────────────────────────┐
22 * │ INTERNAL STRUCTURES │
23 * └─────────────────────────────────────────────────────────────────┘
24 */
25 
26struct PS4Thread {
27 std::thread native;
28 void *(*entry)(void *);
29 void *arg;
30 void *retval;
31 char name[32];
32 bool detached;
33 PS4Emu::Tcb *tcb;
34};
35 
36struct PS4Mutex {
37 std::recursive_mutex native;
38 char name[32];
39 int32_t type;
40};
41 
42struct PS4Cond {
43 std::condition_variable_any native;
44 char name[32];
45};
46 
47struct PS4Rwlock {
48 std::shared_mutex native;
49 char name[32];
50};
51 
52/*
53 * ┌─────────────────────────────────────────────────────────────────┐
54 * │ THREAD REGISTRY │
55 * └─────────────────────────────────────────────────────────────────┘
56 */
57 
58static std::map<ScePthread, PS4Thread *> g_threads;
59static std::mutex g_threads_lock;
60static thread_local PS4Thread *g_current_thread = nullptr;
61 
62// Thread-specific data
63static std::map<uint32_t, std::map<std::thread::id, void *>> g_tsd;
64static std::map<uint32_t, void (*)(void *)> g_tsd_destructors;
65static std::mutex g_tsd_lock;
66static uint32_t g_next_key = 1;
67 
68/*
69 * ┌─────────────────────────────────────────────────────────────────┐
70 * │ THREAD WRAPPER │
71 * └─────────────────────────────────────────────────────────────────┘
72 */
73 
74static void ThreadWrapper(PS4Thread *thrd) {
75 // Set up TLS for this thread
76 thrd->tcb = PS4Emu::CreateTcb();
77 PS4Emu::SetTcbBase(thrd->tcb);
78 g_current_thread = thrd;
79 
80 std::cout << "[PS4Thread] Thread '" << thrd->name << "' started" << std::endl;
81 
82 // Call the actual entry point
83 thrd->retval = thrd->entry(thrd->arg);
84 
85 std::cout << "[PS4Thread] Thread '" << thrd->name << "' exited" << std::endl;
86 
87 // Cleanup TLS
88 PS4Emu::DestroyTcb(thrd->tcb);
89}
90 
91extern "C" {
92 
93/*
94 * ┌─────────────────────────────────────────────────────────────────┐
95 * │ THREAD LIFECYCLE │
96 * └─────────────────────────────────────────────────────────────────┘
97 */
98 
99int32_t scePthreadCreate(ScePthread *thread, const ScePthreadAttr *attr,
100 void *(*entry)(void *), void *arg, const char *name) {
101 std::cout << "[PS4Thread] scePthreadCreate(\"" << (name ? name : "unnamed")
102 << "\")" << std::endl;
103 
104 PS4Thread *thrd = new PS4Thread();
105 thrd->entry = entry;
106 thrd->arg = arg;
107 thrd->retval = nullptr;
108 thrd->detached = false;
109 thrd->tcb = nullptr;
110 strncpy(thrd->name, name ? name : "thread", sizeof(thrd->name) - 1);
111 
112 // Start the thread
113 thrd->native = std::thread(ThreadWrapper, thrd);
114 
115 {
116 std::lock_guard<std::mutex> lock(g_threads_lock);
117 g_threads[thrd] = thrd;
118 }
119 
120 *thread = thrd;
121 return ORBIS_OK;
122}
123 
124int32_t scePthreadJoin(ScePthread thread, void **retval) {
125 PS4Thread *thrd = static_cast<PS4Thread *>(thread);
126 if (!thrd)
127 return ORBIS_KERNEL_ERROR_EINVAL;
128 
129 std::cout << "[PS4Thread] scePthreadJoin(\"" << thrd->name << "\")"
130 << std::endl;
131 
132 if (thrd->native.joinable()) {
133 thrd->native.join();
134 }
135 
136 if (retval) {
137 *retval = thrd->retval;
138 }
139 
140 {
141 std::lock_guard<std::mutex> lock(g_threads_lock);
142 g_threads.erase(thrd);
143 }
144 
145 delete thrd;
146 return ORBIS_OK;
147}
148 
149void scePthreadExit(void *retval) {
150 std::cout << "[PS4Thread] scePthreadExit" << std::endl;
151 if (g_current_thread) {
152 g_current_thread->retval = retval;
153 }
154 // Note: Can't actually exit std::thread from within
155}
156 
157ScePthread scePthreadSelf() { return g_current_thread; }
158 
159int32_t scePthreadCancel(ScePthread thread) {
160 // std::thread doesn't support cancellation
161 std::cout << "[PS4Thread] scePthreadCancel (not implemented)" << std::endl;
162 return ORBIS_OK;
163}
164 
165int32_t scePthreadDetach(ScePthread thread) {
166 PS4Thread *thrd = static_cast<PS4Thread *>(thread);
167 if (!thrd)
168 return ORBIS_KERNEL_ERROR_EINVAL;
169 
170 if (thrd->native.joinable()) {
171 thrd->native.detach();
172 }
173 thrd->detached = true;
174 return ORBIS_OK;
175}
176 
177/*
178 * ┌─────────────────────────────────────────────────────────────────┐
179 * │ THREAD ATTRIBUTES │
180 * └─────────────────────────────────────────────────────────────────┘
181 */
182 
183int32_t scePthreadAttrInit(ScePthreadAttr *attr) {
184 *attr = new uint8_t[64]();
185 return ORBIS_OK;
186}
187 
188int32_t scePthreadAttrDestroy(ScePthreadAttr *attr) {
189 delete[] static_cast<uint8_t *>(*attr);
190 *attr = nullptr;
191 return ORBIS_OK;
192}
193 
194int32_t scePthreadAttrSetdetachstate(ScePthreadAttr *attr, int32_t state) {
195 return ORBIS_OK;
196}
197 
198int32_t scePthreadAttrSetstacksize(ScePthreadAttr *attr, uint64_t size) {
199 return ORBIS_OK;
200}
201 
202int32_t scePthreadAttrSetschedparam(ScePthreadAttr *attr, const void *param) {
203 return ORBIS_OK;
204}
205 
206/*
207 * ┌─────────────────────────────────────────────────────────────────┐
208 * │ MUTEX │
209 * └─────────────────────────────────────────────────────────────────┘
210 */
211 
212int32_t scePthreadMutexInit(ScePthreadMutex *mutex,
213 const ScePthreadMutexattr *attr, const char *name) {
214 PS4Mutex *mtx = new PS4Mutex();
215 mtx->type = SCE_PTHREAD_MUTEX_NORMAL;
216 strncpy(mtx->name, name ? name : "mutex", sizeof(mtx->name) - 1);
217 *mutex = mtx;
218 return ORBIS_OK;
219}
220 
221int32_t scePthreadMutexDestroy(ScePthreadMutex *mutex) {
222 PS4Mutex *mtx = static_cast<PS4Mutex *>(*mutex);
223 if (mtx) {
224 delete mtx;
225 *mutex = nullptr;
226 }
227 return ORBIS_OK;
228}
229 
230int32_t scePthreadMutexLock(ScePthreadMutex *mutex) {
231 PS4Mutex *mtx = static_cast<PS4Mutex *>(*mutex);
232 if (!mtx)
233 return ORBIS_KERNEL_ERROR_EINVAL;
234 mtx->native.lock();
235 return ORBIS_OK;
236}
237 
238int32_t scePthreadMutexTrylock(ScePthreadMutex *mutex) {
239 PS4Mutex *mtx = static_cast<PS4Mutex *>(*mutex);
240 if (!mtx)
241 return ORBIS_KERNEL_ERROR_EINVAL;
242 return mtx->native.try_lock() ? ORBIS_OK : ORBIS_KERNEL_ERROR_EBUSY;
243}
244 
245int32_t scePthreadMutexUnlock(ScePthreadMutex *mutex) {
246 PS4Mutex *mtx = static_cast<PS4Mutex *>(*mutex);
247 if (!mtx)
248 return ORBIS_KERNEL_ERROR_EINVAL;
249 mtx->native.unlock();
250 return ORBIS_OK;
251}
252 
253int32_t scePthreadMutexattrInit(ScePthreadMutexattr *attr) {
254 *attr = new int32_t(SCE_PTHREAD_MUTEX_NORMAL);
255 return ORBIS_OK;
256}
257 
258int32_t scePthreadMutexattrDestroy(ScePthreadMutexattr *attr) {
259 delete static_cast<int32_t *>(*attr);
260 *attr = nullptr;
261 return ORBIS_OK;
262}
263 
264int32_t scePthreadMutexattrSettype(ScePthreadMutexattr *attr, int32_t type) {
265 *static_cast<int32_t *>(*attr) = type;
266 return ORBIS_OK;
267}
268 
269/*
270 * ┌─────────────────────────────────────────────────────────────────┐
271 * │ CONDITION VARIABLE │
272 * └─────────────────────────────────────────────────────────────────┘
273 */
274 
275int32_t scePthreadCondInit(ScePthreadCond *cond, const ScePthreadCondattr *attr,
276 const char *name) {
277 PS4Cond *cv = new PS4Cond();
278 strncpy(cv->name, name ? name : "cond", sizeof(cv->name) - 1);
279 *cond = cv;
280 return ORBIS_OK;
281}
282 
283int32_t scePthreadCondDestroy(ScePthreadCond *cond) {
284 PS4Cond *cv = static_cast<PS4Cond *>(*cond);
285 if (cv) {
286 delete cv;
287 *cond = nullptr;
288 }
289 return ORBIS_OK;
290}
291 
292int32_t scePthreadCondSignal(ScePthreadCond *cond) {
293 PS4Cond *cv = static_cast<PS4Cond *>(*cond);
294 if (!cv)
295 return ORBIS_KERNEL_ERROR_EINVAL;
296 cv->native.notify_one();
297 return ORBIS_OK;
298}
299 
300int32_t scePthreadCondBroadcast(ScePthreadCond *cond) {
301 PS4Cond *cv = static_cast<PS4Cond *>(*cond);
302 if (!cv)
303 return ORBIS_KERNEL_ERROR_EINVAL;
304 cv->native.notify_all();
305 return ORBIS_OK;
306}
307 
308int32_t scePthreadCondWait(ScePthreadCond *cond, ScePthreadMutex *mutex) {
309 PS4Cond *cv = static_cast<PS4Cond *>(*cond);
310 PS4Mutex *mtx = static_cast<PS4Mutex *>(*mutex);
311 if (!cv || !mtx)
312 return ORBIS_KERNEL_ERROR_EINVAL;
313 cv->native.wait(mtx->native);
314 return ORBIS_OK;
315}
316 
317int32_t scePthreadCondTimedwait(ScePthreadCond *cond, ScePthreadMutex *mutex,
318 uint32_t usec) {
319 PS4Cond *cv = static_cast<PS4Cond *>(*cond);
320 PS4Mutex *mtx = static_cast<PS4Mutex *>(*mutex);
321 if (!cv || !mtx)
322 return ORBIS_KERNEL_ERROR_EINVAL;
323 
324 auto status =
325 cv->native.wait_for(mtx->native, std::chrono::microseconds(usec));
326 return status == std::cv_status::timeout ? ORBIS_KERNEL_ERROR_ETIMEDOUT
327 : ORBIS_OK;
328}
329 
330/*
331 * ┌─────────────────────────────────────────────────────────────────┐
332 * │ READ-WRITE LOCK │
333 * └─────────────────────────────────────────────────────────────────┘
334 */
335 
336int32_t scePthreadRwlockInit(ScePthreadRwlock *rwlock,
337 const ScePthreadRwlockattr *attr,
338 const char *name) {
339 PS4Rwlock *rw = new PS4Rwlock();
340 strncpy(rw->name, name ? name : "rwlock", sizeof(rw->name) - 1);
341 *rwlock = rw;
342 return ORBIS_OK;
343}
344 
345int32_t scePthreadRwlockDestroy(ScePthreadRwlock *rwlock) {
346 PS4Rwlock *rw = static_cast<PS4Rwlock *>(*rwlock);
347 if (rw) {
348 delete rw;
349 *rwlock = nullptr;
350 }
351 return ORBIS_OK;
352}
353 
354int32_t scePthreadRwlockRdlock(ScePthreadRwlock *rwlock) {
355 PS4Rwlock *rw = static_cast<PS4Rwlock *>(*rwlock);
356 if (!rw)
357 return ORBIS_KERNEL_ERROR_EINVAL;
358 rw->native.lock_shared();
359 return ORBIS_OK;
360}
361 
362int32_t scePthreadRwlockWrlock(ScePthreadRwlock *rwlock) {
363 PS4Rwlock *rw = static_cast<PS4Rwlock *>(*rwlock);
364 if (!rw)
365 return ORBIS_KERNEL_ERROR_EINVAL;
366 rw->native.lock();
367 return ORBIS_OK;
368}
369 
370int32_t scePthreadRwlockUnlock(ScePthreadRwlock *rwlock) {
371 PS4Rwlock *rw = static_cast<PS4Rwlock *>(*rwlock);
372 if (!rw)
373 return ORBIS_KERNEL_ERROR_EINVAL;
374 // Note: shared_mutex doesn't track read vs write lock
375 // This is a simplification
376 rw->native.unlock();
377 return ORBIS_OK;
378}
379 
380/*
381 * ┌─────────────────────────────────────────────────────────────────┐
382 * │ THREAD-SPECIFIC DATA │
383 * └─────────────────────────────────────────────────────────────────┘
384 */
385 
386int32_t scePthreadKeyCreate(uint32_t *key, void (*destructor)(void *)) {
387 std::lock_guard<std::mutex> lock(g_tsd_lock);
388 uint32_t k = g_next_key++;
389 g_tsd_destructors[k] = destructor;
390 *key = k;
391 return ORBIS_OK;
392}
393 
394int32_t scePthreadKeyDelete(uint32_t key) {
395 std::lock_guard<std::mutex> lock(g_tsd_lock);
396 g_tsd.erase(key);
397 g_tsd_destructors.erase(key);
398 return ORBIS_OK;
399}
400 
401void *scePthreadGetspecific(uint32_t key) {
402 std::lock_guard<std::mutex> lock(g_tsd_lock);
403 auto it = g_tsd.find(key);
404 if (it == g_tsd.end())
405 return nullptr;
406 auto tid = std::this_thread::get_id();
407 auto it2 = it->second.find(tid);
408 return it2 != it->second.end() ? it2->second : nullptr;
409}
410 
411int32_t scePthreadSetspecific(uint32_t key, const void *value) {
412 std::lock_guard<std::mutex> lock(g_tsd_lock);
413 g_tsd[key][std::this_thread::get_id()] = const_cast<void *>(value);
414 return ORBIS_OK;
415}
416 
417/*
418 * ┌─────────────────────────────────────────────────────────────────┐
419 * │ ONCE / YIELD │
420 * └─────────────────────────────────────────────────────────────────┘
421 */
422 
423int32_t scePthreadOnce(void *once_control, void (*init_routine)()) {
424 static std::mutex once_mutex;
425 static std::map<void *, bool> once_done;
426 
427 std::lock_guard<std::mutex> lock(once_mutex);
428 if (!once_done[once_control]) {
429 init_routine();
430 once_done[once_control] = true;
431 }
432 return ORBIS_OK;
433}
434 
435int32_t scePthreadYield() {
436 std::this_thread::yield();
437 return ORBIS_OK;
438}
439 
440} // extern "C"
441