diff --git a/README.md b/README.md index 61ea229..cc82dec 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # shiggy -**sh**immed **iggy** +(sh)immed (iggy) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](https://wiki.vencord.dev/images/a/a3/Shiggy.gif?20240307175550)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif)![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](.github-assets/shiggy.gif) ![](https://wiki.vencord.dev/images/a/a3/Shiggy.gif?20240307175550) \ No newline at end of file diff --git a/include/iggy_audio_shim.h b/include/iggy_audio_shim.h new file mode 100644 index 0000000..d8b09e1 --- /dev/null +++ b/include/iggy_audio_shim.h @@ -0,0 +1,71 @@ +#ifndef IGGY_AUDIO_SHIM_H +#define IGGY_AUDIO_SHIM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define IGGY_AUDIO_OK 0 + +enum IggyAudioOutPort { + Main = 0, + Bgm = 1, + Voice = 2, + Personal = 3, + PadSpk = 4, + Audio3d = 126, + Aux = 127, +}; + +enum IggyAudioOutParamAttr { + None = 0, + Restricted = 1, + MixToMain = 2, +}; + +enum IggyAudioOutParamFormat { + S16Mono = 0, + S16Stereo = 1, + S16_8CH = 2, + FloatMono = 3, + FloatStereo = 4, + Float_8CH = 5, + S16_8CH_Std = 6, + Float_8CH_Std = 7 +}; + +typedef union IggyAudioOutParamExtendedInformation { + unsigned raw; + struct { + unsigned data_format : 8; // bits 0.. 7 + unsigned reserve0 : 8; // bits 8..15 + unsigned attributes : 4; // bits 16..19 + unsigned reserve1 : 10; // bits 20..29 + unsigned : 1; // bit 30 (padding) + unsigned unused : 1; // bit 31 + } bits; +} IggyAudioOutParamExtendedInformation; + + +typedef struct IggyAudioShimCallbacks { + int (*iggyAudioOutOpen)( + int user_id, + enum IggyAudioOutPort port_type, + int index, + unsigned length, + unsigned sample_rate, + IggyAudioOutParamExtendedInformation param_type); + + int (*iggyAudioOutSetVolume)(int handle, int flag, int* vol); + int (*iggyAudioOutClose)(int handle); + int (*iggyAudioOutOutput)(int handle, void* ptr); +} IggyAudioShimCallbacks; + +// Registers callback table used by the shim +int iggyAudioShimRegisterCallbacks(const IggyAudioShimCallbacks* callbacks); + +#ifdef __cplusplus +} +#endif + +#endif // IGGY_AUDIO_SHIM_H diff --git a/meson.build b/meson.build index ebf823b..2da3126 100644 --- a/meson.build +++ b/meson.build @@ -114,8 +114,11 @@ patched_relocations = custom_target( ], ) -libshiggy = static_library( - 'shiggy', - meson.project_source_root() / 'src' / 'shims.c', - objects: patched_relocations, -) +shiggy = declare_dependency( + sources: static_library( + 'shiggy', + meson.project_source_root() / 'src' / 'shims.c', + include_directories : include_directories('include'), + objects: patched_relocations, + ) +) \ No newline at end of file diff --git a/src/shims.c b/src/shims.c index e69de29..7242d95 100644 --- a/src/shims.c +++ b/src/shims.c @@ -0,0 +1,326 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iggy_audio_shim.h" + +_Static_assert(sizeof(pthread_t) == 8, "pthread_t must be 8 bytes"); +_Static_assert(sizeof(int) == 4, "int must be 32 bit"); +_Static_assert(sizeof(unsigned) == 4, "unsigned must be 32 bit"); + + +// MARK: CRT & Math Shims + +double _Sin(double x) { return sin(x); } +double _Log(double x) { return log(x); } + +// Map to the C fenv.h rounding modes +int _Fltrounds(void) { + switch (fegetround()) { + case FE_TOWARDZERO: return 0; + case FE_TONEAREST: return 1; + case FE_DOWNWARD: return 2; + case FE_UPWARD: return 3; + default: return 1; + } +} + +// BSD specific function supposed to return pointer to thread-local errno +#if defined(__GLIBC__) +int *__error(void) { return __errno_location(); } +#else +int *__error(void) { return &errno; } +#endif + +// Microsoft specific variant of gmtime +int gmtime_s(struct tm *tmDest, const time_t *sourceTime) { + if (!tmDest || !sourceTime) return EINVAL; + if (gmtime_r(sourceTime, tmDest) == NULL) return EINVAL; /* conservative */ + return 0; +} + +// Returns pointer to ctype classification table +const unsigned short *_Getpctype(void) { +#if defined(__GLIBC__) + return (const unsigned short *)(*__ctype_b_loc()); +#else + // We might still be alright + errno = ENOSYS; + return NULL; +#endif +} + +// MARK: Helpers for heap-allocated opaque objects + +static int alloc_and_init(void **out, size_t size, int (*init_fn)(void *), void (*free_fn)(void *)) { + if (!out) return EINVAL; + *out = NULL; + + void *p = malloc(size); + if (!p) return ENOMEM; + + int rc = init_fn(p); + if (rc != 0) { + if (free_fn) free_fn(p); + else free(p); + return rc; + } + + *out = p; + return 0; +} + +// MARK: Pthread Shims (opaque handles allocated on heap) + +// Mutex Attributes + +static int mutexattr_init_thunk(void *p) { + return pthread_mutexattr_init((pthread_mutexattr_t *)p); +} + +int scePthreadMutexattrInit(void **attr) { + return alloc_and_init(attr, sizeof(pthread_mutexattr_t), mutexattr_init_thunk, free); +} + +int scePthreadMutexattrSettype(void **attr, int type) { + if (!attr || !*attr) return EINVAL; + return pthread_mutexattr_settype((pthread_mutexattr_t *)*attr, type); +} + +int scePthreadMutexattrDestroy(void **attr) { + if (!attr || !*attr) return EINVAL; + pthread_mutexattr_t *a = (pthread_mutexattr_t *)*attr; + + int rc = pthread_mutexattr_destroy(a); + if (rc == 0) { + free(a); + *attr = NULL; + } + return rc; +} + +// Mutexes + +int scePthreadMutexInit(void **mutex, void **attr, const char *name) { + (void)name; + + if (!mutex) return EINVAL; + *mutex = NULL; + + pthread_mutex_t *m = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); + if (!m) return ENOMEM; + + pthread_mutexattr_t *a = (attr && *attr) ? (pthread_mutexattr_t *)*attr : NULL; + + int rc = pthread_mutex_init(m, a); + if (rc != 0) { + free(m); + return rc; + } + + *mutex = m; + return 0; +} + +int scePthreadMutexLock(void **mutex) { + if (!mutex || !*mutex) return EINVAL; + return pthread_mutex_lock((pthread_mutex_t *)*mutex); +} + +int scePthreadMutexTrylock(void **mutex) { + if (!mutex || !*mutex) return EINVAL; + return pthread_mutex_trylock((pthread_mutex_t *)*mutex); +} + +int scePthreadMutexUnlock(void **mutex) { + if (!mutex || !*mutex) return EINVAL; + return pthread_mutex_unlock((pthread_mutex_t *)*mutex); +} + +int scePthreadMutexTimedlock(void **mutex, unsigned int usecs) { + if (!mutex || !*mutex) return EINVAL; + + struct timespec ts; + + // Get current wall clock time + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) + return errno; + + // Add the relative microseconds to the current time + ts.tv_sec += (usecs / 1000000); + ts.tv_nsec += (usecs % 1000000) * 1000; + + // Handle nanosecond overflow + if (ts.tv_nsec >= 1000000000L) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000L; + } + + // Call the standard POSIX function with the absolute time + return pthread_mutex_timedlock(*mutex, &ts); +} + +int scePthreadMutexDestroy(void **mutex) { + if (!mutex || !*mutex) return EINVAL; + + pthread_mutex_t *m = (pthread_mutex_t *)*mutex; + int rc = pthread_mutex_destroy(m); + if (rc == 0) { + free(m); + *mutex = NULL; + } + return rc; +} + +// Thread Attributes + +static int attr_init_thunk(void *p) { + return pthread_attr_init((pthread_attr_t *)p); +} + +int scePthreadAttrInit(void **attr) { + return alloc_and_init(attr, sizeof(pthread_attr_t), attr_init_thunk, free); +} + +int scePthreadAttrSetstacksize(void **attr, size_t stacksize) { + if (!attr || !*attr) return EINVAL; + return pthread_attr_setstacksize((pthread_attr_t *)*attr, stacksize); +} + +int scePthreadAttrDestroy(void **attr) { + if (!attr || !*attr) return EINVAL; + + pthread_attr_t *a = (pthread_attr_t *)*attr; + int rc = pthread_attr_destroy(a); + if (rc == 0) { + free(a); + *attr = NULL; + } + return rc; +} + +// Threads + +int scePthreadCreate(pthread_t *thread_out, void **attr, void *(*start_routine)(void *), void *arg, const char *name) { + (void)name; + + if (!thread_out || !start_routine) return EINVAL; + pthread_attr_t *a = (attr && *attr) ? (pthread_attr_t *)*attr : NULL; + return pthread_create(thread_out, a, start_routine, arg); +} + +int scePthreadJoin(pthread_t thread, void **value_ptr) { + return pthread_join(thread, value_ptr); +} + +int scePthreadDetach(pthread_t thread) { + return pthread_detach(thread); +} + +pthread_t scePthreadSelf(void) { + return pthread_self(); +} + +void scePthreadYield(void) { + sched_yield(); +} + +int scePthreadSetschedparam(pthread_t thread, int policy, const struct sched_param *param) { + if (!param) return EINVAL; + return pthread_setschedparam(thread, policy, param); +} + +int scePthreadGetschedparam(pthread_t thread, int *policy, struct sched_param *param) { + if (!policy || !param) return EINVAL; + return pthread_getschedparam(thread, policy, param); +} + +// TLS Keys + +int scePthreadKeyCreate(pthread_key_t *key, void (*destructor)(void *), const char *name) { + (void)name; + if (!key) return EINVAL; + return pthread_key_create(key, destructor); +} + +int scePthreadSetspecific(pthread_key_t key, const void *value) { + return pthread_setspecific(key, value); +} + +void *scePthreadGetspecific(pthread_key_t key) { + return pthread_getspecific(key); +} + +// Affinity + +int scePthreadSetaffinity(pthread_t thread, uint64_t cpumask) { + (void)thread; + (void)cpumask; + return 0; // Could return ENOSYS here, but this should be alright too +} + +// MARK: Kernel & Hardware Shims + +int sceKernelGettimeofday(struct timeval *tp) { + if (!tp) return EINVAL; + return gettimeofday(tp, NULL); +} + +int sceKernelUsleep(unsigned microseconds) { + return usleep(microseconds); +} + +// MARK: Audio Shims + +static IggyAudioShimCallbacks g_audioCbs = {}; + +int iggyAudioShimRegisterCallbacks(const IggyAudioShimCallbacks* callbacks) { + if (callbacks) { + g_audioCbs = *callbacks; + } else { + IggyAudioShimCallbacks cbs = {}; + g_audioCbs = cbs; + } + return IGGY_AUDIO_OK; +} + +int sceAudioOutOpen(int user_id, enum IggyAudioOutPort port_type, int index, unsigned length, unsigned sample_rate, IggyAudioOutParamExtendedInformation param_type) { + if (g_audioCbs.iggyAudioOutOpen) + return g_audioCbs.iggyAudioOutOpen(user_id, port_type, index, length, sample_rate, param_type); + return IGGY_AUDIO_OK; +} + +int sceAudioOutSetVolume(int handle, int flag, int* vol) { + if (g_audioCbs.iggyAudioOutSetVolume) + return g_audioCbs.iggyAudioOutSetVolume(handle, flag, vol); + return IGGY_AUDIO_OK; +} + +int sceAudioOutClose(int handle) { + if (g_audioCbs.iggyAudioOutClose) + return g_audioCbs.iggyAudioOutClose(handle); + return IGGY_AUDIO_OK; +} + +int sceAudioOutOutput(int handle, void* ptr) { + if (g_audioCbs.iggyAudioOutOutput) + return g_audioCbs.iggyAudioOutOutput(handle, ptr); + return IGGY_AUDIO_OK; +} + +// MARK: Misc + +void gdraw_ps4_wait(void) { + usleep(1000); +} \ No newline at end of file