2015-02-26 21:08:48 +01:00
|
|
|
#include "stdafx.h"
|
2016-03-21 20:42:14 +01:00
|
|
|
#include "Emu/Cell/PPUModule.h"
|
2017-03-25 22:25:28 +01:00
|
|
|
#include "Utilities/cfmt.h"
|
2015-02-26 21:08:48 +01:00
|
|
|
|
2016-08-19 23:14:10 +02:00
|
|
|
namespace vm { using namespace ps3; }
|
|
|
|
|
|
2016-05-13 15:55:34 +02:00
|
|
|
extern logs::channel sysPrxForUser;
|
2015-02-26 21:08:48 +01:00
|
|
|
|
2016-04-27 00:27:24 +02:00
|
|
|
extern fs::file g_tty;
|
|
|
|
|
|
2017-03-25 22:25:28 +01:00
|
|
|
// cfmt implementation (TODO)
|
|
|
|
|
struct ps3_fmt_src
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-03-25 22:25:28 +01:00
|
|
|
ppu_thread* ctx;
|
|
|
|
|
u32 g_count;
|
|
|
|
|
|
|
|
|
|
bool test(std::size_t index) const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
T get(std::size_t index) const
|
|
|
|
|
{
|
|
|
|
|
const u32 i = (u32)index + g_count;
|
|
|
|
|
return ppu_gpr_cast<T>(i < 8 ? ctx->gpr[3 + i] : +*ctx->get_stack_arg(i));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void skip(std::size_t extra)
|
|
|
|
|
{
|
|
|
|
|
++g_count += (u32)extra;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t fmt_string(std::string& out, std::size_t extra) const
|
|
|
|
|
{
|
|
|
|
|
const std::size_t start = out.size();
|
|
|
|
|
out += vm::ps3::_ptr<const char>(get<u32>(extra));
|
|
|
|
|
return out.size() - start;
|
|
|
|
|
}
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-03-25 22:25:28 +01:00
|
|
|
std::size_t type(std::size_t extra) const
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-03-25 22:25:28 +01:00
|
|
|
return 0;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
2017-05-16 13:29:07 +02:00
|
|
|
|
|
|
|
|
static constexpr std::size_t size_char = 1;
|
|
|
|
|
static constexpr std::size_t size_short = 2;
|
|
|
|
|
static constexpr std::size_t size_int = 4;
|
|
|
|
|
static constexpr std::size_t size_long = 4;
|
|
|
|
|
static constexpr std::size_t size_llong = 8;
|
|
|
|
|
static constexpr std::size_t size_size = 4;
|
|
|
|
|
static constexpr std::size_t size_max = 8;
|
|
|
|
|
static constexpr std::size_t size_diff = 4;
|
2017-03-25 22:25:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
f64 ps3_fmt_src::get<f64>(std::size_t index) const
|
|
|
|
|
{
|
|
|
|
|
const u64 value = get<u64>(index);
|
|
|
|
|
return *reinterpret_cast<const f64*>(reinterpret_cast<const u8*>(&value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string ps3_fmt(ppu_thread& context, vm::cptr<char> fmt, u32 g_count)
|
|
|
|
|
{
|
|
|
|
|
std::string result;
|
|
|
|
|
|
|
|
|
|
cfmt_append(result, fmt.get_ptr(), ps3_fmt_src{&context, g_count});
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm::ptr<void> _sys_memset(vm::ptr<void> dst, s32 value, u32 size)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sysPrxForUser.trace("_sys_memset(dst=*0x%x, value=%d, size=0x%x)", dst, value, size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
std::memset(dst.get_ptr(), value, size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm::ptr<void> _sys_memcpy(vm::ptr<void> dst, vm::cptr<void> src, u32 size)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sysPrxForUser.trace("_sys_memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
std::memcpy(dst.get_ptr(), src.get_ptr(), size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_memcmp(vm::cptr<void> buf1, vm::cptr<void> buf2, u32 size)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sysPrxForUser.trace("_sys_memcmp(buf1=*0x%x, buf2=*0x%x, size=%d)", buf1, buf2, size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
return std::memcmp(buf1.get_ptr(), buf2.get_ptr(), size);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_memchr()
|
|
|
|
|
{
|
2016-08-08 18:01:06 +02:00
|
|
|
fmt::throw_exception("Unimplemented" HERE);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-16 19:54:09 +01:00
|
|
|
vm::ptr<void> _sys_memmove(vm::ptr<void> dst, vm::cptr<void> src, u32 size)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2016-02-16 19:54:09 +01:00
|
|
|
sysPrxForUser.trace("_sys_memmove(dst=*0x%x, src=*0x%x, size=%d)", dst, src, size);
|
|
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
std::memmove(dst.get_ptr(), src.get_ptr(), size);
|
2016-02-16 19:54:09 +01:00
|
|
|
|
|
|
|
|
return dst;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s64 _sys_strlen(vm::cptr<char> str)
|
|
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strlen(str=%s)", str);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
return std::strlen(str.get_ptr());
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_strcmp(vm::cptr<char> str1, vm::cptr<char> str2)
|
|
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strcmp(str1=%s, str2=%s)", str1, str2);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
return std::strcmp(str1.get_ptr(), str2.get_ptr());
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_strncmp(vm::cptr<char> str1, vm::cptr<char> str2, s32 max)
|
|
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strncmp(str1=%s, str2=%s, max=%d)", str1, str2, max);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
return std::strncmp(str1.get_ptr(), str2.get_ptr(), max);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm::ptr<char> _sys_strcat(vm::ptr<char> dest, vm::cptr<char> source)
|
|
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strcat(dest=*0x%x, source=%s)", dest, source);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-15 02:11:49 +02:00
|
|
|
verify(HERE), std::strcat(dest.get_ptr(), source.get_ptr()) == dest.get_ptr();
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm::cptr<char> _sys_strchr(vm::cptr<char> str, s32 ch)
|
|
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strchr(str=%s, ch=0x%x)", str, ch);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return vm::cptr<char>::make(vm::get_addr(strchr(str.get_ptr(), ch)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm::ptr<char> _sys_strncat(vm::ptr<char> dest, vm::cptr<char> source, u32 len)
|
|
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strncat(dest=*0x%x, source=%s, len=%d)", dest, source, len);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-15 02:11:49 +02:00
|
|
|
verify(HERE), std::strncat(dest.get_ptr(), source.get_ptr(), len) == dest.get_ptr();
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm::ptr<char> _sys_strcpy(vm::ptr<char> dest, vm::cptr<char> source)
|
|
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strcpy(dest=*0x%x, source=%s)", dest, source);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-15 02:11:49 +02:00
|
|
|
verify(HERE), std::strcpy(dest.get_ptr(), source.get_ptr()) == dest.get_ptr();
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm::ptr<char> _sys_strncpy(vm::ptr<char> dest, vm::cptr<char> source, u32 len)
|
|
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strncpy(dest=*0x%x, source=%s, len=%d)", dest, source, len);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
if (!dest || !source)
|
|
|
|
|
{
|
|
|
|
|
return vm::null;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-15 02:11:49 +02:00
|
|
|
verify(HERE), std::strncpy(dest.get_ptr(), source.get_ptr(), len) == dest.get_ptr();
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_strncasecmp()
|
|
|
|
|
{
|
2016-08-08 18:01:06 +02:00
|
|
|
fmt::throw_exception("Unimplemented" HERE);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_strrchr()
|
|
|
|
|
{
|
2016-08-08 18:01:06 +02:00
|
|
|
fmt::throw_exception("Unimplemented" HERE);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_tolower()
|
|
|
|
|
{
|
2016-08-08 18:01:06 +02:00
|
|
|
fmt::throw_exception("Unimplemented" HERE);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_toupper()
|
|
|
|
|
{
|
2016-08-08 18:01:06 +02:00
|
|
|
fmt::throw_exception("Unimplemented" HERE);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 _sys_malloc(u32 size)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sysPrxForUser.warning("_sys_malloc(size=0x%x)", size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return vm::alloc(size, vm::main);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 _sys_memalign(u32 align, u32 size)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sysPrxForUser.warning("_sys_memalign(align=0x%x, size=0x%x)", align, size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return vm::alloc(size, vm::main, std::max<u32>(align, 4096));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_free(u32 addr)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sysPrxForUser.warning("_sys_free(addr=0x%x)", addr);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
vm::dealloc(addr, vm::main);
|
|
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
s32 _sys_snprintf(ppu_thread& ppu, vm::ptr<char> dst, u32 count, vm::cptr<char> fmt, ppu_va_args_t va_args)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.warning("_sys_snprintf(dst=*0x%x, count=%d, fmt=%s, ...)", dst, count, fmt);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-03-21 20:42:14 +01:00
|
|
|
std::string result = ps3_fmt(ppu, fmt, va_args.count);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
if (!count)
|
|
|
|
|
{
|
|
|
|
|
return 0; // ???
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
count = (u32)std::min<size_t>(count - 1, result.size());
|
|
|
|
|
|
2017-03-25 22:25:28 +01:00
|
|
|
std::memcpy(dst.get_ptr(), result.c_str(), count);
|
2015-08-02 04:15:49 +02:00
|
|
|
dst[count] = 0;
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
s32 _sys_printf(ppu_thread& ppu, vm::cptr<char> fmt, ppu_va_args_t va_args)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.warning("_sys_printf(fmt=%s, ...)", fmt);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-04-27 00:27:24 +02:00
|
|
|
if (g_tty)
|
|
|
|
|
{
|
|
|
|
|
g_tty.write(ps3_fmt(ppu, fmt, va_args.count));
|
|
|
|
|
}
|
2015-07-28 22:05:44 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-25 22:25:28 +01:00
|
|
|
s32 _sys_sprintf(ppu_thread& ppu, vm::ptr<char> buffer, vm::cptr<char> fmt, ppu_va_args_t va_args)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-03-25 22:25:28 +01:00
|
|
|
sysPrxForUser.warning("_sys_sprintf(buffer=*0x%x, fmt=%s, ...)", buffer, fmt);
|
|
|
|
|
|
|
|
|
|
std::string result = ps3_fmt(ppu, fmt, va_args.count);
|
|
|
|
|
|
|
|
|
|
std::memcpy(buffer.get_ptr(), result.c_str(), result.size() + 1);
|
|
|
|
|
|
|
|
|
|
return static_cast<s32>(result.size());
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_vprintf()
|
|
|
|
|
{
|
2016-08-08 18:01:06 +02:00
|
|
|
fmt::throw_exception("Unimplemented" HERE);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_vsnprintf()
|
|
|
|
|
{
|
2016-08-08 18:01:06 +02:00
|
|
|
fmt::throw_exception("Unimplemented" HERE);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_vsprintf()
|
|
|
|
|
{
|
2016-08-08 18:01:06 +02:00
|
|
|
fmt::throw_exception("Unimplemented" HERE);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_qsort()
|
|
|
|
|
{
|
2016-08-08 18:01:06 +02:00
|
|
|
fmt::throw_exception("Unimplemented" HERE);
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sysPrxForUser_sys_libc_init()
|
|
|
|
|
{
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memset);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memcpy);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memcmp);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memchr);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memmove);
|
|
|
|
|
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strlen);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strcmp);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strncmp);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strcat);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strchr);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strncat);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strcpy);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strncpy);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strncasecmp);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strrchr);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_tolower);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_toupper);
|
|
|
|
|
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_malloc);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memalign);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_free);
|
|
|
|
|
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_snprintf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_printf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_sprintf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_vprintf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_vsnprintf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_vsprintf);
|
|
|
|
|
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_qsort);
|
|
|
|
|
}
|