mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-02-20 08:22:02 -07:00
Libs.LibcInternal: _Fofind, _Lockfilelock, _Unlockfilelock, _Foprep, _Fopen, fopen, fflush, _Nnl, _Fspos, fseek, _Frprep, fread, _Fofree, fclose, _Mtxinit, _Mtxlock, _Mtxunlock, _Mtxdst implementations (#4019)
* Initial definitions * internal__Fofind * Libcinternal threads fopen stores a valid pthread mutex in the FILE struct. Since this is exposed to the game/app, we need to handle this accurately. * internal__Foprep (and various other functions called in it) * Actual fopen implementation At long last, an actual function I'm supposed to implement. * fflush + compile fixes * fseek implementation Comes with functions fseek calls, aside from fflush which I pushed earlier. * fread, _Frprep Also changed some parameter names a tad to match how I named things in my decomp. And fixed some bugs with how I was handling the weird offseted mode thing * fclose, _Fofree Not confident on this one, but we'll see I guess. * Bug fixing No more crashes at least, fread seems to be broken though. * fopen bugfixes Behavior now matches LLE, at least in how LLE font seems to use it. * Fix _Frprep Seems like everything works now? * Logging Probably going to need to swap lseek and read logs to debug/trace later but this is for debugging. * Remove alignment check Seems I must've misinterpreted some of what Ghidra spat out, since libSceNgs2 is calling with size 1, nmemb 4. * Reduce fseek, fread logs to trace * Clang
This commit is contained in:
parent
99661aa6b3
commit
6a7f8a9e5a
@ -496,6 +496,8 @@ set(HLE_LIBC_INTERNAL_LIB src/core/libraries/libc_internal/libc_internal.cpp
|
||||
src/core/libraries/libc_internal/libc_internal_str.h
|
||||
src/core/libraries/libc_internal/libc_internal_math.cpp
|
||||
src/core/libraries/libc_internal/libc_internal_math.h
|
||||
src/core/libraries/libc_internal/libc_internal_threads.cpp
|
||||
src/core/libraries/libc_internal/libc_internal_threads.h
|
||||
src/core/libraries/libc_internal/printf.h
|
||||
)
|
||||
|
||||
|
||||
@ -65,6 +65,9 @@ constexpr int ORBIS_KERNEL_O_DSYNC = 0x1000;
|
||||
constexpr int ORBIS_KERNEL_O_DIRECT = 0x00010000;
|
||||
constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000;
|
||||
|
||||
s32 PS4_SYSV_ABI posix_open(const char* path, s32 flags, u16 mode);
|
||||
s32 PS4_SYSV_ABI posix_close(s32 fd);
|
||||
s64 PS4_SYSV_ABI posix_lseek(s32 fd, s64 offset, s32 whence);
|
||||
s64 PS4_SYSV_ABI sceKernelWrite(s32 fd, const void* buf, u64 nbytes);
|
||||
s64 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, u64 nbytes);
|
||||
s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, u64 nbytes, s64 offset);
|
||||
|
||||
@ -28,6 +28,16 @@ int PS4_SYSV_ABI posix_pthread_create(PthreadT* thread, const PthreadAttrT* attr
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_join(PthreadT pthread, void** thread_return);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_mutexattr_init(PthreadMutexAttrT* attr);
|
||||
int PS4_SYSV_ABI posix_pthread_mutexattr_settype(PthreadMutexAttrT* attr, PthreadMutexType type);
|
||||
int PS4_SYSV_ABI posix_pthread_mutexattr_destroy(PthreadMutexAttrT* attr);
|
||||
|
||||
int PS4_SYSV_ABI scePthreadMutexInit(PthreadMutexT* mutex, const PthreadMutexAttrT* mutex_attr,
|
||||
const char* name);
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_lock(PthreadMutexT* mutex);
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_unlock(PthreadMutexT* mutex);
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_destroy(PthreadMutexT* mutex);
|
||||
|
||||
void RegisterThreads(Core::Loader::SymbolsResolver* sym);
|
||||
|
||||
class Thread {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "libc_internal_math.h"
|
||||
#include "libc_internal_memory.h"
|
||||
#include "libc_internal_str.h"
|
||||
#include "libc_internal_threads.h"
|
||||
#include "printf.h"
|
||||
|
||||
namespace Libraries::LibcInternal {
|
||||
@ -20,5 +21,11 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||
RegisterlibSceLibcInternalStr(sym);
|
||||
RegisterlibSceLibcInternalMemory(sym);
|
||||
RegisterlibSceLibcInternalIo(sym);
|
||||
RegisterlibSceLibcInternalThreads(sym);
|
||||
}
|
||||
|
||||
void ForceRegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||
// Used to forcibly enable HLEs for broken LLE functions.
|
||||
ForceRegisterlibSceLibcInternalIo(sym);
|
||||
}
|
||||
} // namespace Libraries::LibcInternal
|
||||
@ -15,4 +15,5 @@ namespace Libraries::LibcInternal {
|
||||
// so everything is just in the .cpp file
|
||||
|
||||
void RegisterLib(Core::Loader::SymbolsResolver* sym);
|
||||
void ForceRegisterLib(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::LibcInternal
|
||||
@ -3,21 +3,484 @@
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
|
||||
#include <common/va_ctx.h>
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/file_system.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/kernel/posix_error.h"
|
||||
#include "core/libraries/libc_internal/libc_internal_io.h"
|
||||
#include "core/libraries/libc_internal/libc_internal_threads.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "libc_internal_io.h"
|
||||
#include "printf.h"
|
||||
|
||||
namespace Libraries::LibcInternal {
|
||||
int PS4_SYSV_ABI internal_snprintf(char* s, size_t n, VA_ARGS) {
|
||||
|
||||
s32 PS4_SYSV_ABI internal_snprintf(char* s, u64 n, VA_ARGS) {
|
||||
VA_CTX(ctx);
|
||||
return snprintf_ctx(s, n, &ctx);
|
||||
}
|
||||
|
||||
std::map<s32, OrbisFILE*> g_files{};
|
||||
// Constants for tracking accurate file indexes.
|
||||
// Since the file struct is exposed to the application, accuracy is important.
|
||||
static constexpr s32 g_initial_files = 5;
|
||||
static constexpr s32 g_max_files = 0x100;
|
||||
|
||||
OrbisFILE* PS4_SYSV_ABI internal__Fofind() {
|
||||
u64 index = g_initial_files;
|
||||
while (index != g_max_files) {
|
||||
OrbisFILE* file = g_files[index];
|
||||
// If file doesn't exist, create it.
|
||||
if (file == nullptr) {
|
||||
file = new OrbisFILE();
|
||||
if (file == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
// Store new file in the array, initialize default values, and return it.
|
||||
g_files[index] = file;
|
||||
file->_Mode = 0x80;
|
||||
file->_Idx = index;
|
||||
return file;
|
||||
}
|
||||
// Special case, files with mode 0 are returned?
|
||||
if (file->_Mode == 0) {
|
||||
file->_Mode = 0xff7f;
|
||||
return file;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI internal__Lockfilelock(OrbisFILE* file) {
|
||||
if (file != nullptr && file->_Mutex != nullptr) {
|
||||
internal__Mtxlock(&file->_Mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI internal__Unlockfilelock(OrbisFILE* file) {
|
||||
if (file != nullptr && file->_Mutex != nullptr) {
|
||||
internal__Mtxunlock(&file->_Mutex);
|
||||
}
|
||||
}
|
||||
|
||||
OrbisFILE* PS4_SYSV_ABI internal__Foprep(const char* path, const char* mode, OrbisFILE* file,
|
||||
s32 fd, s32 s_mode, s32 flag) {
|
||||
if (file == nullptr) {
|
||||
*Kernel::__Error() = POSIX_ENOMEM;
|
||||
}
|
||||
|
||||
// Preserve mode and index
|
||||
Libraries::Kernel::PthreadMutexT mtx = file->_Mutex;
|
||||
Libraries::Kernel::PthreadMutexT* mtx_ptr = &file->_Mutex;
|
||||
u8 file_index = file->_Idx;
|
||||
u16 file_mode = file->_Mode & 0x80;
|
||||
|
||||
// Real library does a memcpy using a static global FILE object.
|
||||
// This stored file is just zeros, with the only exception being a handle of -1.
|
||||
memset(file, 0, sizeof(OrbisFILE));
|
||||
file->_Handle = -1;
|
||||
|
||||
// Not sure what this magic is for, but I'll replicate it.
|
||||
u8* ptr = &file->_Cbuf;
|
||||
// Note: this field is supposed to be a pthread mutex.
|
||||
// Since we don't export pthread HLEs for other functions, I'll avoid handling this for now.
|
||||
file->_Mutex = nullptr;
|
||||
file->_Idx = file_index;
|
||||
file->_Buf = ptr;
|
||||
file->_Bend = &file->unk2;
|
||||
file->_Next = ptr;
|
||||
file->_Rend = ptr;
|
||||
file->_WRend = ptr;
|
||||
file->_Wend = ptr;
|
||||
file->_WWend = ptr;
|
||||
file->_Rback = ptr;
|
||||
file->_WRback = &file->unk1;
|
||||
|
||||
// Parse inputted mode string
|
||||
const char* mode_str = mode;
|
||||
u16 calc_mode = 0;
|
||||
u16 access_mode = 0;
|
||||
if (mode_str[0] == 'r') {
|
||||
calc_mode = 1 | file_mode;
|
||||
} else if (mode_str[0] == 'w') {
|
||||
calc_mode = 0x1a | file_mode;
|
||||
} else if (mode_str[0] == 'a') {
|
||||
calc_mode = 0x16 | file_mode;
|
||||
} else {
|
||||
// Closes the file and returns EINVAL.
|
||||
file->_Mode = file_mode;
|
||||
if (flag == 0) {
|
||||
internal__Mtxinit(mtx_ptr, nullptr);
|
||||
} else {
|
||||
file->_Mutex = mtx;
|
||||
internal__Unlockfilelock(file);
|
||||
}
|
||||
internal_fclose(file);
|
||||
*Kernel::__Error() = POSIX_EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
file->_Mode = calc_mode;
|
||||
|
||||
do {
|
||||
// This is all basically straight from decomp, need to cleanup at some point.
|
||||
if (mode_str[1] == '+') {
|
||||
file_mode = 3;
|
||||
if ((~calc_mode & 3) == 0) {
|
||||
break;
|
||||
}
|
||||
} else if (mode_str[1] != 'b') {
|
||||
file_mode = 0x20;
|
||||
if ((calc_mode & 0x20) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mode_str++;
|
||||
calc_mode = file_mode | calc_mode;
|
||||
file->_Mode = calc_mode;
|
||||
} while (true);
|
||||
|
||||
if (path == nullptr && fd >= 0) {
|
||||
// I guess this is for some internal behavior?
|
||||
file->_Handle = fd;
|
||||
} else {
|
||||
fd = internal__Fopen(path, calc_mode, s_mode == 0x55);
|
||||
file->_Handle = fd;
|
||||
}
|
||||
|
||||
// Error case
|
||||
if (fd < 0) {
|
||||
// Closes the file, but ensures errno is unchanged.
|
||||
if (flag == 0) {
|
||||
internal__Mtxinit(mtx_ptr, nullptr);
|
||||
} else {
|
||||
file->_Mutex = mtx;
|
||||
internal__Unlockfilelock(file);
|
||||
}
|
||||
s32 old_errno = *Kernel::__Error();
|
||||
internal_fclose(file);
|
||||
*Kernel::__Error() = old_errno;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (flag == 0) {
|
||||
char mtx_name[0x20];
|
||||
std::snprintf(mtx_name, 0x20, "FileFD:0x%08X", fd);
|
||||
internal__Mtxinit(mtx_ptr, mtx_name);
|
||||
} else {
|
||||
file->_Mutex = mtx;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal__Fopen(const char* path, u16 mode, bool flag) {
|
||||
u32 large_mode = mode;
|
||||
u16 open_mode = 0600;
|
||||
if (!flag) {
|
||||
open_mode = 0666;
|
||||
}
|
||||
// Straight from decomp, should probably get cleaned up at some point.
|
||||
s32 creat_flag = large_mode << 5 & 0x200;
|
||||
s32 excl_flag = large_mode << 5 & 0x800;
|
||||
s32 misc_flags = (large_mode & 8) * 0x80 + (large_mode & 4) * 2;
|
||||
// Real library has an array for this, where large_mode & 3 is used as an index.
|
||||
// That array has values [0, 0, 1, 2], so this call should match the result.
|
||||
s32 access_flag = std::max<s32>((large_mode & 3) - 1, 0);
|
||||
s32 open_flags = creat_flag | misc_flags | excl_flag | access_flag;
|
||||
return Libraries::Kernel::posix_open(path, open_flags, open_mode);
|
||||
}
|
||||
|
||||
OrbisFILE* PS4_SYSV_ABI internal_fopen(const char* path, const char* mode) {
|
||||
std::scoped_lock lk{g_file_mtx};
|
||||
LOG_INFO(Lib_LibcInternal, "called, path {}, mode {}", path, mode);
|
||||
OrbisFILE* file = internal__Fofind();
|
||||
return internal__Foprep(path, mode, file, -1, 0, 0);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal_fflush(OrbisFILE* file) {
|
||||
if (file == nullptr) {
|
||||
std::scoped_lock lk{g_file_mtx};
|
||||
s32 fflush_result = 0;
|
||||
for (auto& file : g_files) {
|
||||
s32 res = internal_fflush(file.second);
|
||||
if (res < 0) {
|
||||
fflush_result = -1;
|
||||
}
|
||||
}
|
||||
return fflush_result;
|
||||
}
|
||||
if ((file->_Mode & 0x2000) != 0) {
|
||||
internal__Lockfilelock(file);
|
||||
u16 file_mode = file->_Mode;
|
||||
u8* file_buf_start = file->_Buf;
|
||||
u8* file_buf_end = file->_Next;
|
||||
while (file_buf_start < file_buf_end) {
|
||||
u64 size_to_write = static_cast<u64>(file_buf_end - file_buf_start);
|
||||
s32 write_bytes =
|
||||
Libraries::Kernel::sceKernelWrite(file->_Handle, file_buf_start, size_to_write);
|
||||
if (write_bytes < 1) {
|
||||
file_buf_start = file->_Buf;
|
||||
file->_Next = file_buf_start;
|
||||
file->_Wend = file_buf_start;
|
||||
file->_WWend = file_buf_start;
|
||||
u8* off_mode = reinterpret_cast<u8*>(&file->_Mode) + 1;
|
||||
*off_mode = *off_mode | 2;
|
||||
internal__Unlockfilelock(file);
|
||||
return -1;
|
||||
}
|
||||
file_buf_end = file->_Next;
|
||||
file_buf_start += write_bytes;
|
||||
}
|
||||
file->_Next = file_buf_start;
|
||||
file->_Wend = file_buf_start;
|
||||
file->_WWend = file_buf_start;
|
||||
file->_Mode = file_mode & 0xdfff;
|
||||
internal__Unlockfilelock(file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 PS4_SYSV_ABI internal__Nnl(OrbisFILE* file, u8* val1, u8* val2) {
|
||||
if (val1 < val2) {
|
||||
return val2 - val1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal__Fspos(OrbisFILE* file, Orbisfpos_t* file_pos, s64 offset, s32 whence) {
|
||||
if ((file->_Mode & 3) == 0) {
|
||||
return -1;
|
||||
}
|
||||
if (internal_fflush(file) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (whence >= 3) {
|
||||
*Libraries::Kernel::__Error() = POSIX_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (file_pos != nullptr) {
|
||||
offset = offset + file_pos->_Off;
|
||||
}
|
||||
if (whence == 1 && (file->_Mode & 0x1000) != 0) {
|
||||
s64 val1 = internal__Nnl(file, file->_Rback, &file->_Cbuf);
|
||||
u8* rsave_ptr = file->_Rsave;
|
||||
if (rsave_ptr == nullptr) {
|
||||
rsave_ptr = file->_Rend;
|
||||
}
|
||||
s64 val2 = internal__Nnl(file, file->_Next, rsave_ptr);
|
||||
s64 val3 = internal__Nnl(file, file->_Next, file->_WRend);
|
||||
offset = offset - (val1 + val2 + val3);
|
||||
}
|
||||
s64 result = 0;
|
||||
if (whence == 2 || (whence == 1 && offset != 0) || (whence == 0 && offset != -1)) {
|
||||
result = Libraries::Kernel::posix_lseek(file->_Handle, offset, whence);
|
||||
}
|
||||
if (result == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
u16 file_mode = file->_Mode;
|
||||
if ((file_mode & 0x3000) != 0) {
|
||||
u8* file_buf = file->_Buf;
|
||||
file->_Next = file_buf;
|
||||
file->_Rend = file_buf;
|
||||
file->_WRend = file_buf;
|
||||
file->_Wend = file_buf;
|
||||
file->_WWend = file_buf;
|
||||
file->_Rback = &file->_Cbuf;
|
||||
file->_WRback = &file->unk1;
|
||||
file->_Rsave = nullptr;
|
||||
}
|
||||
if (file_pos != nullptr) {
|
||||
std::memcpy(&file->_Wstate, &file_pos->_Wstate, sizeof(Orbis_Mbstatet));
|
||||
}
|
||||
file->_Mode = file_mode & 0xceff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal_fseek(OrbisFILE* file, s64 offset, s32 whence) {
|
||||
internal__Lockfilelock(file);
|
||||
LOG_TRACE(Lib_LibcInternal, "called, file handle {:#x}, offset {:#x}, whence {:#x}",
|
||||
file->_Handle, offset, whence);
|
||||
s32 result = internal__Fspos(file, nullptr, offset, whence);
|
||||
internal__Unlockfilelock(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal__Frprep(OrbisFILE* file) {
|
||||
if (file->_Rend > file->_Next) {
|
||||
return 1;
|
||||
}
|
||||
if ((file->_Mode & 0x100) != 0) {
|
||||
return 0;
|
||||
}
|
||||
u16 mode = file->_Mode;
|
||||
if ((mode & 0xa001) != 1) {
|
||||
// Lot of magic here, might be valuable to figure out what this does.
|
||||
file->_Mode = (((mode ^ 0x8000) >> 0xf) << 0xe) | mode | 0x200;
|
||||
return -1;
|
||||
}
|
||||
|
||||
u8* file_buf = file->_Buf;
|
||||
if ((mode & 0x800) == 0 && file_buf == &file->_Cbuf) {
|
||||
// Allocate a new file buffer, for now, we'll use host malloc to create it.
|
||||
// When we have an HLE for malloc, that should be used instead.
|
||||
u8* new_buffer = std::bit_cast<u8*>(std::malloc(0x10000));
|
||||
if (new_buffer == nullptr) {
|
||||
file->_Buf = file_buf;
|
||||
file->_Bend = file_buf + 1;
|
||||
} else {
|
||||
file->_Mode = file->_Mode | 0x40;
|
||||
file->_Buf = new_buffer;
|
||||
file->_Bend = new_buffer + 0x10000;
|
||||
file->_WRend = new_buffer;
|
||||
file->_WWend = new_buffer;
|
||||
file_buf = new_buffer;
|
||||
}
|
||||
}
|
||||
file->_Next = file_buf;
|
||||
file->_Rend = file_buf;
|
||||
file->_Wend = file_buf;
|
||||
// Intentional shrinking here, library treats value as 32-bit.
|
||||
s32 read_result =
|
||||
Libraries::Kernel::sceKernelRead(file->_Handle, file_buf, file->_Bend - file_buf);
|
||||
if (read_result < 0) {
|
||||
u8* off_mode = reinterpret_cast<u8*>(&file->_Mode) + 1;
|
||||
*off_mode = *off_mode | 0x42;
|
||||
return -1;
|
||||
} else if (read_result != 0) {
|
||||
file->_Mode = file->_Mode | 0x5000;
|
||||
file->_Rend = file->_Rend + read_result;
|
||||
return 1;
|
||||
}
|
||||
file->_Mode = (file->_Mode & 0xaeff) | 0x4100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 PS4_SYSV_ABI internal_fread(char* ptr, u64 size, u64 nmemb, OrbisFILE* file) {
|
||||
if (size == 0 || nmemb == 0) {
|
||||
return 0;
|
||||
}
|
||||
internal__Lockfilelock(file);
|
||||
LOG_TRACE(Lib_LibcInternal, "called, file handle {:#x}, size {:#x}, nmemb {:#x}", file->_Handle,
|
||||
size, nmemb);
|
||||
s64 total_size = size * nmemb;
|
||||
s64 remaining_size = total_size;
|
||||
if ((file->_Mode & 0x4000) != 0) {
|
||||
while (remaining_size != 0) {
|
||||
u8* rback_ptr = file->_Rback;
|
||||
if (&file->_Cbuf <= rback_ptr) {
|
||||
break;
|
||||
}
|
||||
file->_Rback = rback_ptr + 1;
|
||||
*ptr = *rback_ptr;
|
||||
ptr++;
|
||||
remaining_size--;
|
||||
}
|
||||
}
|
||||
|
||||
while (remaining_size != 0) {
|
||||
u8* file_ptr = file->_Rsave;
|
||||
if (file_ptr == nullptr) {
|
||||
file_ptr = file->_Rend;
|
||||
} else {
|
||||
file->_Rend = file_ptr;
|
||||
file->_Rsave = nullptr;
|
||||
}
|
||||
u8* src = file->_Next;
|
||||
if (file_ptr <= src) {
|
||||
s32 res = internal__Frprep(file);
|
||||
if (res < 1) {
|
||||
internal__Unlockfilelock(file);
|
||||
return (total_size - remaining_size) / size;
|
||||
}
|
||||
src = file->_Next;
|
||||
file_ptr = file->_Rend;
|
||||
}
|
||||
u64 copy_bytes = std::min<u64>(file_ptr - src, remaining_size);
|
||||
std::memcpy(ptr, src, copy_bytes);
|
||||
file->_Next += copy_bytes;
|
||||
ptr += copy_bytes;
|
||||
remaining_size -= copy_bytes;
|
||||
}
|
||||
internal__Unlockfilelock(file);
|
||||
return (total_size - remaining_size) / size;
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI internal__Fofree(OrbisFILE* file) {
|
||||
u8* cbuf_ptr = &file->_Cbuf;
|
||||
s8 trunc_mode = static_cast<s8>(file->_Mode);
|
||||
|
||||
file->_Mode = 0;
|
||||
file->_Handle = -1;
|
||||
file->_Buf = cbuf_ptr;
|
||||
file->_Next = cbuf_ptr;
|
||||
file->_Rend = cbuf_ptr;
|
||||
file->_WRend = cbuf_ptr;
|
||||
file->_Wend = cbuf_ptr;
|
||||
file->_WWend = cbuf_ptr;
|
||||
file->_Rback = cbuf_ptr;
|
||||
file->_WRback = &file->unk1;
|
||||
if (trunc_mode < 0) {
|
||||
// Remove file from vector
|
||||
g_files.erase(file->_Idx);
|
||||
internal__Mtxdst(&file->_Mutex);
|
||||
free(file);
|
||||
}
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal_fclose(OrbisFILE* file) {
|
||||
if (file == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_INFO(Lib_LibcInternal, "called, file handle {:#x}", file->_Handle);
|
||||
if ((file->_Mode & 3) == 0 || file->_Handle < 0) {
|
||||
std::scoped_lock lk{g_file_mtx};
|
||||
internal__Fofree(file);
|
||||
*Libraries::Kernel::__Error() = POSIX_EBADF;
|
||||
} else {
|
||||
s32 fflush_result = internal_fflush(file);
|
||||
std::scoped_lock lk{g_file_mtx};
|
||||
if ((file->_Mode & 0x40) != 0) {
|
||||
std::free(file->_Buf);
|
||||
}
|
||||
file->_Buf = nullptr;
|
||||
s32 close_result = Libraries::Kernel::posix_close(file->_Handle);
|
||||
internal__Fofree(file);
|
||||
// Need to figure out what exactly this means.
|
||||
return ~-(close_result == 0) | fflush_result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterlibSceLibcInternalIo(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("eLdDw6l0-bU", "libSceLibcInternal", 1, "libSceLibcInternal", internal_snprintf);
|
||||
LIB_FUNCTION("MUjC4lbHrK4", "libSceLibcInternal", 1, "libSceLibcInternal", internal_fflush);
|
||||
LIB_FUNCTION("xGT4Mc55ViQ", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Fofind);
|
||||
LIB_FUNCTION("dREVnZkAKRE", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Foprep);
|
||||
LIB_FUNCTION("sQL8D-jio7U", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Fopen);
|
||||
LIB_FUNCTION("A+Y3xfrWLLo", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Fspos);
|
||||
LIB_FUNCTION("Ss3108pBuZY", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Nnl);
|
||||
LIB_FUNCTION("9s3P+LCvWP8", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Frprep);
|
||||
LIB_FUNCTION("jVDuvE3s5Bs", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Fofree);
|
||||
LIB_FUNCTION("vZkmJmvqueY", "libSceLibcInternal", 1, "libSceLibcInternal",
|
||||
internal__Lockfilelock);
|
||||
LIB_FUNCTION("0x7rx8TKy2Y", "libSceLibcInternal", 1, "libSceLibcInternal",
|
||||
internal__Unlockfilelock);
|
||||
}
|
||||
|
||||
void ForceRegisterlibSceLibcInternalIo(Core::Loader::SymbolsResolver* sym) {
|
||||
// Goal is to be minimally intrusive here to allow LLE for printf/stdout writes.
|
||||
LIB_FUNCTION("xeYO4u7uyJ0", "libSceLibcInternal", 1, "libSceLibcInternal", internal_fopen);
|
||||
LIB_FUNCTION("rQFVBXp-Cxg", "libSceLibcInternal", 1, "libSceLibcInternal", internal_fseek);
|
||||
LIB_FUNCTION("lbB+UlZqVG0", "libSceLibcInternal", 1, "libSceLibcInternal", internal_fread);
|
||||
LIB_FUNCTION("uodLYyUip20", "libSceLibcInternal", 1, "libSceLibcInternal", internal_fclose);
|
||||
}
|
||||
|
||||
} // namespace Libraries::LibcInternal
|
||||
@ -3,12 +3,96 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::LibcInternal {
|
||||
|
||||
static std::recursive_mutex g_file_mtx{};
|
||||
|
||||
union Orbis__mbstate_t {
|
||||
u8 __mbstate8[128];
|
||||
s64 _mbstateL;
|
||||
};
|
||||
|
||||
struct Orbis_Mbstatet {
|
||||
u64 _Wchar;
|
||||
u16 _Byte, _State;
|
||||
s32 : 32;
|
||||
};
|
||||
|
||||
struct Orbisfpos_t {
|
||||
s64 _Off;
|
||||
Orbis_Mbstatet _Wstate;
|
||||
};
|
||||
|
||||
struct Orbis__sbuf {
|
||||
u8* _base;
|
||||
s32 _size;
|
||||
};
|
||||
|
||||
struct OrbisFILE {
|
||||
u16 _Mode;
|
||||
u8 _Idx;
|
||||
s32 _Handle;
|
||||
u8 *_Buf, *_Bend, *_Next;
|
||||
u8 *_Rend, *_Wend, *_Rback;
|
||||
u16 *_WRback, _WBack[2];
|
||||
u16 unk1;
|
||||
u8 *_Rsave, *_WRend, *_WWend;
|
||||
Orbis_Mbstatet _Wstate;
|
||||
u8* _Tmpnam;
|
||||
u8 _Back[6], _Cbuf;
|
||||
u8 unk2;
|
||||
Libraries::Kernel::PthreadMutexT _Mutex;
|
||||
u8* _p;
|
||||
s32 _r;
|
||||
s32 _w;
|
||||
s16 _flags;
|
||||
s16 _file;
|
||||
Orbis__sbuf _bf;
|
||||
s32 _lbfsize;
|
||||
void* _cookie;
|
||||
s32 PS4_SYSV_ABI (*_close)(void*);
|
||||
s32 PS4_SYSV_ABI (*_read)(void*, char*, s32);
|
||||
Orbisfpos_t PS4_SYSV_ABI (*_seek)(void*, Orbisfpos_t, s32);
|
||||
s32 (*_write)(void*, const char*, s32);
|
||||
Orbis__sbuf _ub;
|
||||
u8* _up;
|
||||
s32 _ur;
|
||||
u8 _ubuf[3];
|
||||
u8 _nbuf[1];
|
||||
Orbis__sbuf _lb;
|
||||
s32 _blksize;
|
||||
Orbisfpos_t _offset;
|
||||
void* _fl_mutex;
|
||||
void* _fl_owner;
|
||||
s32 _fl_count;
|
||||
s32 _orientation;
|
||||
Orbis__mbstate_t _mbstate;
|
||||
};
|
||||
|
||||
s32 PS4_SYSV_ABI internal_snprintf(char* s, u64 n, VA_ARGS);
|
||||
void PS4_SYSV_ABI internal__Lockfilelock(OrbisFILE* file);
|
||||
void PS4_SYSV_ABI internal__Unlockfilelock(OrbisFILE* file);
|
||||
OrbisFILE* PS4_SYSV_ABI internal__Fofind();
|
||||
OrbisFILE* PS4_SYSV_ABI internal__Foprep(const char* path, const char* mode, OrbisFILE* file,
|
||||
s32 fd, s32 flag1, s32 flag2);
|
||||
s32 PS4_SYSV_ABI internal__Fopen(const char* path, u16 mode, bool flag);
|
||||
OrbisFILE* PS4_SYSV_ABI internal_fopen(const char* path, const char* mode);
|
||||
s64 PS4_SYSV_ABI internal__Nnl(OrbisFILE* file, u8* val1, u8* val2);
|
||||
s32 PS4_SYSV_ABI internal__Fspos(OrbisFILE* file, Orbisfpos_t* file_pos, s64 offset, s32 whence);
|
||||
s32 PS4_SYSV_ABI internal_fflush(OrbisFILE* file);
|
||||
s32 PS4_SYSV_ABI internal_fseek(OrbisFILE* file, s64 offset, s32 whence);
|
||||
s32 PS4_SYSV_ABI internal__Frprep(OrbisFILE* file);
|
||||
u64 PS4_SYSV_ABI internal_fread(char* ptr, u64 size, u64 nmemb, OrbisFILE* file);
|
||||
s32 PS4_SYSV_ABI internal_fclose(OrbisFILE* file);
|
||||
|
||||
void RegisterlibSceLibcInternalIo(Core::Loader::SymbolsResolver* sym);
|
||||
void ForceRegisterlibSceLibcInternalIo(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::LibcInternal
|
||||
65
src/core/libraries/libc_internal/libc_internal_threads.cpp
Normal file
65
src/core/libraries/libc_internal/libc_internal_threads.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
#include "core/libraries/libc_internal/libc_internal_threads.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::LibcInternal {
|
||||
|
||||
void getMutexName(char* buf, u64 size, const char* name) {
|
||||
if (name != nullptr) {
|
||||
std::snprintf(buf, size, "SceLibcI_%s", name);
|
||||
} else {
|
||||
std::snprintf(buf, size, "SceLibcI");
|
||||
}
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal__Mtxinit(Libraries::Kernel::PthreadMutexT* mtx, const char* name) {
|
||||
char mtx_name[0x20];
|
||||
getMutexName(mtx_name, sizeof(mtx_name), name);
|
||||
|
||||
Libraries::Kernel::PthreadMutexAttrT attr{};
|
||||
s32 result = Libraries::Kernel::posix_pthread_mutexattr_init(&attr);
|
||||
if (result != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = Libraries::Kernel::posix_pthread_mutexattr_settype(
|
||||
&attr, Libraries::Kernel::PthreadMutexType::Recursive);
|
||||
if (result == 0) {
|
||||
s32 mtx_init_result = Libraries::Kernel::scePthreadMutexInit(mtx, &attr, mtx_name);
|
||||
result = Libraries::Kernel::posix_pthread_mutexattr_destroy(&attr);
|
||||
if (mtx_init_result == 0 && result == 0) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
Libraries::Kernel::posix_pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal__Mtxlock(Libraries::Kernel::PthreadMutexT* mtx) {
|
||||
s32 result = Libraries::Kernel::posix_pthread_mutex_lock(mtx);
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal__Mtxunlock(Libraries::Kernel::PthreadMutexT* mtx) {
|
||||
s32 result = Libraries::Kernel::posix_pthread_mutex_unlock(mtx);
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI internal__Mtxdst(Libraries::Kernel::PthreadMutexT* mtx) {
|
||||
s32 result = Libraries::Kernel::posix_pthread_mutex_destroy(mtx);
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
void RegisterlibSceLibcInternalThreads(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("z7STeF6abuU", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Mtxinit);
|
||||
LIB_FUNCTION("pE4Ot3CffW0", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Mtxlock);
|
||||
LIB_FUNCTION("cMwgSSmpE5o", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Mtxunlock);
|
||||
LIB_FUNCTION("LaPaA6mYA38", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Mtxdst);
|
||||
}
|
||||
|
||||
} // namespace Libraries::LibcInternal
|
||||
22
src/core/libraries/libc_internal/libc_internal_threads.h
Normal file
22
src/core/libraries/libc_internal/libc_internal_threads.h
Normal file
@ -0,0 +1,22 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::LibcInternal {
|
||||
|
||||
s32 PS4_SYSV_ABI internal__Mtxinit(Libraries::Kernel::PthreadMutexT* mtx, const char* name);
|
||||
s32 PS4_SYSV_ABI internal__Mtxlock(Libraries::Kernel::PthreadMutexT* mtx);
|
||||
s32 PS4_SYSV_ABI internal__Mtxunlock(Libraries::Kernel::PthreadMutexT* mtx);
|
||||
s32 PS4_SYSV_ABI internal__Mtxdst(Libraries::Kernel::PthreadMutexT* mtx);
|
||||
|
||||
void RegisterlibSceLibcInternalThreads(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::LibcInternal
|
||||
@ -80,6 +80,7 @@ namespace Libraries {
|
||||
void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
||||
LOG_INFO(Lib_Kernel, "Initializing HLE libraries");
|
||||
Libraries::Kernel::RegisterLib(sym);
|
||||
Libraries::LibcInternal::ForceRegisterLib(sym);
|
||||
Libraries::GnmDriver::RegisterLib(sym);
|
||||
Libraries::VideoOut::RegisterLib(sym);
|
||||
Libraries::UserService::RegisterLib(sym);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user