Merge pull request #1925 from Nekotekina/master

Commit collection
This commit is contained in:
Ivan 2016-07-17 03:44:28 +03:00 committed by GitHub
commit 260865de6d
40 changed files with 1438 additions and 1233 deletions

View File

@ -327,14 +327,44 @@ inline v128 operator ~(const v128& other)
#define IS_INTEGER(t) (std::is_integral<t>::value || std::is_enum<t>::value)
#define IS_BINARY_COMPARABLE(t1, t2) (IS_INTEGER(t1) && IS_INTEGER(t2) && sizeof(t1) == sizeof(t2))
template<typename T, std::size_t Size = sizeof(T)>
template<typename T, std::size_t Align, std::size_t Size>
struct se_storage
{
static_assert(!Size, "Bad se_storage<> type");
using type = std::aligned_storage_t<Size, Align>;
// Unoptimized generic byteswap for unaligned data
static void reverse(u8* dst, const u8* src)
{
for (std::size_t i = 0; i < Size; i++)
{
dst[i] = src[Size - 1 - i];
}
}
static type to(const T& src)
{
type result;
reverse(reinterpret_cast<u8*>(&result), reinterpret_cast<const u8*>(&src));
return result;
}
static T from(const type& src)
{
T result;
reverse(reinterpret_cast<u8*>(&result), reinterpret_cast<const u8*>(&src));
return result;
}
static type copy(const type& src)
{
type result;
std::memcpy(&result, &src, Size);
return result;
}
};
template<typename T>
struct se_storage<T, 2>
struct se_storage<T, 2, 2>
{
using type = u16;
@ -357,10 +387,15 @@ struct se_storage<T, 2>
const u16 result = swap(src);
return reinterpret_cast<const T&>(result);
}
static inline T copy(const T& src)
{
return src;
}
};
template<typename T>
struct se_storage<T, 4>
struct se_storage<T, 4, 4>
{
using type = u32;
@ -383,10 +418,15 @@ struct se_storage<T, 4>
const u32 result = swap(src);
return reinterpret_cast<const T&>(result);
}
static inline T copy(const T& src)
{
return src;
}
};
template<typename T>
struct se_storage<T, 8>
struct se_storage<T, 8, 8>
{
using type = u64;
@ -409,10 +449,15 @@ struct se_storage<T, 8>
const u64 result = swap(src);
return reinterpret_cast<const T&>(result);
}
static inline T copy(const T& src)
{
return src;
}
};
template<typename T>
struct se_storage<T, 16>
struct se_storage<T, 16, 16>
{
using type = v128;
@ -431,43 +476,22 @@ struct se_storage<T, 16>
const v128 result = swap(src);
return reinterpret_cast<const T&>(result);
}
};
template<typename T> using se_storage_t = typename se_storage<T>::type;
template<typename T1, typename T2>
struct se_convert
{
using type_from = std::remove_cv_t<T1>;
using type_to = std::remove_cv_t<T2>;
using stype_from = se_storage_t<std::remove_cv_t<T1>>;
using stype_to = se_storage_t<std::remove_cv_t<T2>>;
using storage_from = se_storage<std::remove_cv_t<T1>>;
using storage_to = se_storage<std::remove_cv_t<T2>>;
static inline std::enable_if_t<std::is_same<type_from, type_to>::value, stype_to> convert(const stype_from& data)
static inline T copy(const T& src)
{
return data;
}
static inline stype_to convert(const stype_from& data, ...)
{
return storage_to::to(storage_from::from(data));
return src;
}
};
static struct se_raw_tag_t {} constexpr se_raw{};
template<typename T, bool Se = true>
class se_t;
// Switched endianness
template<typename T>
class se_t<T, true>
template<typename T, std::size_t Align>
class se_t<T, true, Align>
{
using type = typename std::remove_cv<T>::type;
using stype = se_storage_t<type>;
using storage = se_storage<type>;
using stype = typename se_storage<type, Align>::type;
using storage = se_storage<type, Align>;
stype m_data;
@ -585,39 +609,41 @@ public:
};
// Native endianness
template<typename T>
class se_t<T, false>
template<typename T, std::size_t Align>
class se_t<T, false, Align>
{
using type = typename std::remove_cv<T>::type;
using stype = typename se_storage<type, Align>::type;
using storage = se_storage<type, Align>;
static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)");
static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)");
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment");
type m_data;
stype m_data;
public:
se_t() = default;
constexpr se_t(type value)
: m_data(value)
se_t(type value)
: m_data(reinterpret_cast<const stype&>(value))
{
}
// Construct directly from raw data (don't use)
constexpr se_t(const type& raw_value, const se_raw_tag_t&)
constexpr se_t(const stype& raw_value, const se_raw_tag_t&)
: m_data(raw_value)
{
}
constexpr type value() const
type value() const
{
return m_data;
return storage::copy(reinterpret_cast<const type&>(m_data));
}
// Access underlying raw data (don't use)
constexpr const type& raw_data() const noexcept
constexpr const stype& raw_data() const noexcept
{
return m_data;
}
@ -626,14 +652,14 @@ public:
se_t& operator =(type value)
{
return m_data = value, *this;
return m_data = reinterpret_cast<const stype&>(value), *this;
}
using simple_type = simple_t<T>;
constexpr operator type() const
operator type() const
{
return m_data;
return storage::copy(reinterpret_cast<const type&>(m_data));
}
template<typename CT>
@ -656,59 +682,59 @@ public:
};
// se_t with native endianness (alias)
template<typename T> using nse_t = se_t<T, false>;
template<typename T, std::size_t Align = alignof(T)> using nse_t = se_t<T, false, Align>;
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator +=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, std::size_t Align, typename T1>
inline se_t<T, Se, Align>& operator +=(se_t<T, Se, Align>& left, const T1& right)
{
auto value = left.value();
return left = (value += right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator -=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, std::size_t Align, typename T1>
inline se_t<T, Se, Align>& operator -=(se_t<T, Se, Align>& left, const T1& right)
{
auto value = left.value();
return left = (value -= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator *=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, std::size_t Align, typename T1>
inline se_t<T, Se, Align>& operator *=(se_t<T, Se, Align>& left, const T1& right)
{
auto value = left.value();
return left = (value *= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator /=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, std::size_t Align, typename T1>
inline se_t<T, Se, Align>& operator /=(se_t<T, Se, Align>& left, const T1& right)
{
auto value = left.value();
return left = (value /= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator %=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, std::size_t Align, typename T1>
inline se_t<T, Se, Align>& operator %=(se_t<T, Se, Align>& left, const T1& right)
{
auto value = left.value();
return left = (value %= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator <<=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, std::size_t Align, typename T1>
inline se_t<T, Se, Align>& operator <<=(se_t<T, Se, Align>& left, const T1& right)
{
auto value = left.value();
return left = (value <<= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator >>=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, std::size_t Align, typename T1>
inline se_t<T, Se, Align>& operator >>=(se_t<T, Se, Align>& left, const T1& right)
{
auto value = left.value();
return left = (value >>= right);
}
template<typename T, bool Se>
inline se_t<T, Se> operator ++(se_t<T, Se>& left, int)
template<typename T, bool Se, std::size_t Align>
inline se_t<T, Se, Align> operator ++(se_t<T, Se, Align>& left, int)
{
auto value = left.value();
auto result = value++;
@ -716,8 +742,8 @@ inline se_t<T, Se> operator ++(se_t<T, Se>& left, int)
return result;
}
template<typename T, bool Se>
inline se_t<T, Se> operator --(se_t<T, Se>& left, int)
template<typename T, bool Se, std::size_t Align>
inline se_t<T, Se, Align> operator --(se_t<T, Se, Align>& left, int)
{
auto value = left.value();
auto result = value--;
@ -725,15 +751,15 @@ inline se_t<T, Se> operator --(se_t<T, Se>& left, int)
return result;
}
template<typename T, bool Se>
inline se_t<T, Se>& operator ++(se_t<T, Se>& right)
template<typename T, bool Se, std::size_t Align>
inline se_t<T, Se, Align>& operator ++(se_t<T, Se, Align>& right)
{
auto value = right.value();
return right = ++value;
}
template<typename T, bool Se>
inline se_t<T, Se>& operator --(se_t<T, Se>& right)
template<typename T, bool Se, std::size_t Align>
inline se_t<T, Se, Align>& operator --(se_t<T, Se, Align>& right)
{
auto value = right.value();
return right = --value;
@ -852,16 +878,28 @@ inline std::enable_if_t<std::is_integral<T>::value && sizeof(T) >= 4, se_t<declt
}
#if IS_LE_MACHINE == 1
template<typename T> using be_t = se_t<T, true>;
template<typename T> using le_t = se_t<T, false>;
template<typename T, std::size_t Align = alignof(T)> using be_t = se_t<T, true, Align>;
template<typename T, std::size_t Align = alignof(T)> using le_t = se_t<T, false, Align>;
#endif
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type
template<typename T, bool Se, typename = void>
struct to_se
{
template<typename T2, typename = void>
struct to_se_
{
using type = T2;
};
template<typename T2>
struct to_se_<T2, std::enable_if_t<std::is_arithmetic<T2>::value || std::is_enum<T2>::value>>
{
using type = se_t<T2, Se>;
};
// Convert arithmetic and enum types
using type = typename std::conditional<std::is_arithmetic<T>::value || std::is_enum<T>::value, se_t<T, Se>, T>::type;
using type = typename to_se_<T>::type;
};
template<bool Se> struct to_se<v128, Se> { using type = se_t<v128, Se>; };
@ -911,10 +949,10 @@ template<typename T> using atomic_le_t = atomic_t<le_t<T>>;
#endif
// Formatting for BE/LE data
template<typename T, bool Se>
struct unveil<se_t<T, Se>, void>
template<typename T, bool Se, std::size_t Align>
struct unveil<se_t<T, Se, Align>, void>
{
static inline auto get(const se_t<T, Se>& arg)
static inline auto get(const se_t<T, Se, Align>& arg)
{
return unveil<T>::get(arg);
}

View File

@ -80,6 +80,8 @@ static fs::error to_error(DWORD e)
case ERROR_ALREADY_EXISTS: return fs::error::exist;
case ERROR_FILE_EXISTS: return fs::error::exist;
case ERROR_NEGATIVE_SEEK: return fs::error::inval;
case ERROR_DIRECTORY: return fs::error::inval;
case ERROR_INVALID_NAME: return fs::error::inval;
default: throw fmt::exception("Unknown Win32 error: %u.", e);
}
}

View File

@ -12,6 +12,7 @@
#define _XOPEN_SOURCE
#define __USE_GNU
#endif
#include <errno.h>
#include <signal.h>
#include <ucontext.h>
#endif
@ -1608,6 +1609,8 @@ static void prepare_throw_access_violation(x64_context* context, const char* cau
RIP(context) = (u64)std::addressof(throw_access_violation);
}
static void _handle_interrupt(x64_context* ctx);
#ifdef _WIN32
static LONG exception_handler(PEXCEPTION_POINTERS pExp)
@ -1697,6 +1700,11 @@ static void signal_handler(int sig, siginfo_t* info, void* uct)
{
x64_context* context = (ucontext_t*)uct;
if (sig == SIGUSR1)
{
return _handle_interrupt(context);
}
#ifdef __APPLE__
const bool is_writing = context->uc_mcontext->__es.__err & 0x2;
#else
@ -1734,7 +1742,15 @@ const bool s_exception_handler_set = []() -> bool
if (::sigaction(SIGSEGV, &sa, NULL) == -1)
{
std::printf("sigaction() failed (0x%x).", errno);
std::printf("sigaction(SIGSEGV) failed (0x%x).", errno);
std::abort();
}
sa.sa_sigaction = signal_handler;
if (::sigaction(SIGUSR1, &sa, NULL) == -1)
{
std::printf("sigaction(SIGUSR1) failed (0x%x).", errno);
std::abort();
}
@ -1766,13 +1782,23 @@ struct thread_ctrl::internal
{
std::mutex mutex;
std::condition_variable cond;
std::condition_variable join; // Allows simultaneous joining
std::condition_variable jcv; // Allows simultaneous joining
std::condition_variable icv;
task_stack atexit;
std::exception_ptr exception; // Caught exception
std::exception_ptr exception; // Stored exception
std::chrono::high_resolution_clock::time_point time_limit;
#ifdef _WIN32
DWORD thread_id = 0;
x64_context _context{};
#endif
x64_context* thread_ctx{};
atomic_t<void(*)()> interrupt{}; // Interrupt function
};
thread_local thread_ctrl::internal* g_tls_internal = nullptr;
@ -1803,7 +1829,6 @@ void thread_ctrl::start(const std::shared_ptr<thread_ctrl>& ctrl, task_stack tas
}
catch (...)
{
ctrl->initialize_once();
ctrl->m_data->exception = std::current_exception();
}
@ -1813,15 +1838,11 @@ void thread_ctrl::start(const std::shared_ptr<thread_ctrl>& ctrl, task_stack tas
void thread_ctrl::wait_start(u64 timeout)
{
initialize_once();
m_data->time_limit = std::chrono::high_resolution_clock::now() + std::chrono::microseconds(timeout);
}
bool thread_ctrl::wait_wait(u64 timeout)
{
initialize_once();
std::unique_lock<std::mutex> lock(m_data->mutex, std::adopt_lock);
if (timeout && m_data->cond.wait_until(lock, m_data->time_limit) == std::cv_status::timeout)
@ -1845,11 +1866,12 @@ void thread_ctrl::test()
void thread_ctrl::initialize()
{
initialize_once(); // TODO (temporarily)
// Initialize TLS variable
g_tls_this_thread = this;
g_tls_internal = this->m_data;
#ifdef _WIN32
m_data->thread_id = GetCurrentThreadId();
#endif
g_tls_log_prefix = []
{
@ -1891,6 +1913,10 @@ void thread_ctrl::initialize()
void thread_ctrl::finalize() noexcept
{
// Disable and discard possible interrupts
interrupt_disable();
test_interrupt();
// TODO
vm::reservation_free();
@ -1908,7 +1934,6 @@ void thread_ctrl::finalize() noexcept
void thread_ctrl::push_atexit(task_stack task)
{
initialize_once();
m_data->atexit.push(std::move(task));
}
@ -1921,6 +1946,8 @@ thread_ctrl::thread_ctrl(std::string&& name)
#undef new
new (&m_thread) std::thread;
#pragma pop_macro("new")
initialize_once();
}
thread_ctrl::~thread_ctrl()
@ -1966,24 +1993,20 @@ void thread_ctrl::join()
// Notify others if necessary
if (UNLIKELY(m_joining.exchange(0x80000000) != 1))
{
initialize_once();
// Serialize for reliable notification
m_data->mutex.lock();
m_data->mutex.unlock();
m_data->join.notify_all();
m_data->jcv.notify_all();
}
}
else
{
// Hard way
initialize_once();
std::unique_lock<std::mutex> lock(m_data->mutex);
m_data->join.wait(lock, WRAP_EXPR(m_joining >= 0x80000000));
m_data->jcv.wait(lock, WRAP_EXPR(m_joining >= 0x80000000));
}
if (UNLIKELY(m_data && m_data->exception))
if (UNLIKELY(m_data && m_data->exception && !std::uncaught_exception()))
{
std::rethrow_exception(m_data->exception);
}
@ -1991,7 +2014,6 @@ void thread_ctrl::join()
void thread_ctrl::lock()
{
initialize_once();
m_data->mutex.lock();
}
@ -2007,8 +2029,6 @@ void thread_ctrl::lock_notify()
return;
}
initialize_once();
// Serialize for reliable notification, condition is assumed to be changed externally
m_data->mutex.lock();
m_data->mutex.unlock();
@ -2025,6 +2045,116 @@ void thread_ctrl::set_exception(std::exception_ptr e)
m_data->exception = e;
}
static void _handle_interrupt(x64_context* ctx)
{
g_tls_internal->thread_ctx = ctx;
thread_ctrl::handle_interrupt();
}
void thread_ctrl::handle_interrupt()
{
const auto _this = g_tls_this_thread;
const auto ctx = g_tls_internal->thread_ctx;
if (_this->m_guard & 0x80000000)
{
// Discard interrupt if interrupts are disabled
if (g_tls_internal->interrupt.exchange(nullptr))
{
_this->lock();
_this->unlock();
g_tls_internal->icv.notify_one();
}
}
else if (_this->m_guard == 0)
{
// Set interrupt immediately if no guard set
if (const auto handler = g_tls_internal->interrupt.exchange(nullptr))
{
_this->lock();
_this->unlock();
g_tls_internal->icv.notify_one();
// Install function call
*--(u64*&)(RSP(ctx)) = RIP(ctx);
RIP(ctx) = (u64)handler;
}
}
else
{
// Set delayed interrupt otherwise
_this->m_guard |= 0x40000000;
}
#ifdef _WIN32
RtlRestoreContext(ctx, nullptr);
#endif
}
void thread_ctrl::interrupt(void(*handler)())
{
VERIFY(this != g_tls_this_thread); // TODO: self-interrupt
VERIFY(m_data->interrupt.compare_and_swap_test(nullptr, handler)); // TODO: multiple interrupts
#ifdef _WIN32
const auto ctx = &m_data->_context;
m_data->thread_ctx = ctx;
const HANDLE nt = OpenThread(THREAD_ALL_ACCESS, FALSE, m_data->thread_id);
VERIFY(nt);
VERIFY(SuspendThread(nt) != -1);
ctx->ContextFlags = CONTEXT_FULL;
VERIFY(GetThreadContext(nt, ctx));
ctx->ContextFlags = CONTEXT_FULL;
const u64 _rip = RIP(ctx);
RIP(ctx) = (u64)std::addressof(thread_ctrl::handle_interrupt);
VERIFY(SetThreadContext(nt, ctx));
RIP(ctx) = _rip;
VERIFY(ResumeThread(nt) != -1);
CloseHandle(nt);
#else
pthread_kill(reinterpret_cast<std::thread&>(m_thread).native_handle(), SIGUSR1);
#endif
std::unique_lock<std::mutex> lock(m_data->mutex, std::adopt_lock);
while (m_data->interrupt)
{
m_data->icv.wait(lock);
}
lock.release();
}
void thread_ctrl::test_interrupt()
{
if (m_guard & 0x80000000)
{
if (m_data->interrupt.exchange(nullptr))
{
lock(), unlock(), m_data->icv.notify_one();
}
return;
}
if (m_guard == 0x40000000 && !std::uncaught_exception())
{
m_guard = 0;
// Execute delayed interrupt handler
if (const auto handler = m_data->interrupt.exchange(nullptr))
{
lock(), unlock(), m_data->icv.notify_one();
return handler();
}
}
}
void thread_ctrl::sleep(u64 useconds)
{
std::this_thread::sleep_for(std::chrono::microseconds(useconds));

View File

@ -94,6 +94,9 @@ private:
// Thread join contention counter
atomic_t<u32> m_joining{};
// Thread interrupt guard counter
u32 m_guard = 0x80000000;
// Thread internals
atomic_t<internal*> m_data{};
@ -187,6 +190,42 @@ public:
// Set exception (internal data must be initialized, thread mutex must be locked)
void set_exception(std::exception_ptr);
// Internal
static void handle_interrupt();
// Interrupt thread with specified handler call (thread mutex must be locked)
void interrupt(void(*handler)());
// Interrupt guard recursive enter
void guard_enter()
{
m_guard++;
}
// Interrupt guard recursive leave
void guard_leave()
{
if (UNLIKELY(--m_guard & 0x40000000))
{
test_interrupt();
}
}
// Allow interrupts
void interrupt_enable()
{
m_guard &= ~0x80000000;
}
// Disable and discard any interrupt
void interrupt_disable()
{
m_guard |= 0x80000000;
}
// Check interrupt if delayed by guard scope
void test_interrupt();
// Current thread sleeps for specified amount of microseconds.
// Wrapper for std::this_thread::sleep, doesn't require valid thread_ctrl.
[[deprecated]] static void sleep(u64 useconds);
@ -352,6 +391,36 @@ public:
}
};
// Interrupt guard scope
class thread_guard final
{
thread_ctrl* m_thread;
public:
thread_guard(const thread_guard&) = delete;
thread_guard(thread_ctrl* thread)
: m_thread(thread)
{
m_thread->guard_enter();
}
thread_guard(named_thread& thread)
: thread_guard(thread.operator->())
{
}
thread_guard()
: thread_guard(thread_ctrl::get_current())
{
}
~thread_guard() noexcept(false)
{
m_thread->guard_leave();
}
};
// Wrapper for named thread, joins automatically in the destructor, can only be used in function scope
class scope_thread final
{

View File

@ -103,3 +103,46 @@ public:
});
}
};
//! Simple lock-free map. Based on lf_array<>. All elements are accessible, implicitly initialized.
template<typename K, typename T, typename Hash = value_hash<K>, std::size_t Size = 256>
class lf_hashmap
{
struct pair_t
{
// Default-constructed key means "no key"
atomic_t<K> key{};
T value{};
};
//
lf_array<pair_t, Size> m_data{};
// Value for default-constructed key
T m_default_key_data{};
public:
constexpr lf_hashmap() = default;
// Access element (added implicitly)
T& operator [](const K& key)
{
if (UNLIKELY(key == K{}))
{
return m_default_key_data;
}
// Calculate hash and array position
for (std::size_t pos = Hash{}(key) % Size;; pos += Size)
{
// Access the array
auto& pair = m_data[pos];
// Check the key value (optimistic)
if (LIKELY(pair.key == key) || pair.key.compare_and_swap_test(K{}, key))
{
return pair.value;
}
}
}
};

View File

@ -34,6 +34,12 @@ struct bijective_pair
T2 v2;
};
template<typename T, std::size_t Align = alignof(T), std::size_t Size = sizeof(T)>
struct se_storage;
template<typename T, bool Se = true, std::size_t Align = alignof(T)>
class se_t;
// Specialization with static constexpr bijective_pair<T1, T2> map[] member expected
template<typename T1, typename T2>
struct bijective;
@ -417,6 +423,15 @@ struct pointer_hash
}
};
template<typename T, std::size_t Shift = 0>
struct value_hash
{
std::size_t operator()(T value) const
{
return static_cast<std::size_t>(value) >> Shift;
}
};
// Contains value of any POD type with fixed size and alignment. TT<> is the type converter applied.
// For example, `simple_t` may be used to remove endianness.
template<template<typename> class TT, std::size_t S, std::size_t A = S>

View File

@ -58,8 +58,13 @@ s32 cellFsReaddir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
{
cellFs.trace("cellFsReaddir(fd=0x%x, dir=*0x%x, nread=*0x%x)", fd, dir, nread);
if (!dir || !nread)
{
return CELL_EFAULT;
}
// call the syscall
return dir && nread ? sys_fs_readdir(fd, dir, nread) : CELL_FS_EFAULT;
return sys_fs_readdir(fd, dir, nread);
}
s32 cellFsClosedir(u32 fd)
@ -132,8 +137,13 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr<u64> pos)
{
cellFs.trace("cellFsLseek(fd=0x%x, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos);
if (!pos)
{
return CELL_EFAULT;
}
// call the syscall
return pos ? sys_fs_lseek(fd, offset, whence, pos) : CELL_FS_EFAULT;
return sys_fs_lseek(fd, offset, whence, pos);
}
s32 cellFsFsync(u32 fd)
@ -147,8 +157,13 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_siz
{
cellFs.trace("cellFsFGetBlockSize(fd=0x%x, sector_size=*0x%x, block_size=*0x%x)", fd, sector_size, block_size);
if (!sector_size || !block_size)
{
return CELL_EFAULT;
}
// call the syscall
return sector_size && block_size ? sys_fs_fget_block_size(fd, sector_size, block_size, vm::var<u64>{}, vm::var<u64>{}) : CELL_FS_EFAULT;
return sys_fs_fget_block_size(fd, sector_size, block_size, vm::var<u64>{}, vm::var<u64>{});
}
s32 cellFsGetBlockSize(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size)
@ -205,11 +220,11 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr<CellFsDirectoryEntry> entries, u32
{
cellFs.warning("cellFsGetDirectoryEntries(fd=%d, entries=*0x%x, entries_size=0x%x, data_count=*0x%x)", fd, entries, entries_size, data_count);
const auto directory = idm::get<lv2_dir_t>(fd);
const auto directory = idm::get<lv2_dir>(fd);
if (!directory)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
u32 count = 0;
@ -246,474 +261,278 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr<CellFsDirectoryEntry> entries, u32
return CELL_OK;
}
s32 cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr<void> buf, u64 buffer_size, vm::ptr<u64> nread)
ppu_error_code cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr<void> buf, u64 buffer_size, vm::ptr<u64> nread)
{
cellFs.trace("cellFsReadWithOffset(fd=%d, offset=0x%llx, buf=*0x%x, buffer_size=0x%llx, nread=*0x%x)", fd, offset, buf, buffer_size, nread);
// TODO: use single sys_fs_fcntl syscall
const auto file = idm::get<lv2_file_t>(fd);
if (!file || file->flags & CELL_FS_O_WRONLY)
if (fd - 3 > 252)
{
return CELL_FS_EBADF;
if (nread) *nread = 0;
return CELL_EBADF;
}
std::lock_guard<std::mutex> lock(file->mutex);
vm::var<lv2_file_op_rw> arg;
const auto old_pos = file->file.pos(); file->file.seek(offset);
arg->_vtable = vm::cast(0xfa8a0000); // Intentionally wrong (provide correct vtable if necessary)
arg->op = 0x8000000a;
arg->fd = fd;
arg->buf = buf;
arg->offset = offset;
arg->size = buffer_size;
const auto read = file->file.read(buf.get_ptr(), buffer_size);
// Call the syscall
const s32 rc = sys_fs_fcntl(fd, 0x8000000a, arg, arg.size());
file->file.seek(old_pos);
// Write size read
if (nread) *nread = rc && rc != CELL_EFSSPECIFIC ? 0 : arg->out_size.value();
if (nread)
{
*nread = read;
}
return CELL_OK;
return NOT_AN_ERROR(rc ? rc : arg->out_code.value());
}
s32 cellFsWriteWithOffset(u32 fd, u64 offset, vm::cptr<void> buf, u64 data_size, vm::ptr<u64> nwrite)
ppu_error_code cellFsWriteWithOffset(u32 fd, u64 offset, vm::cptr<void> buf, u64 data_size, vm::ptr<u64> nwrite)
{
cellFs.trace("cellFsWriteWithOffset(fd=%d, offset=0x%llx, buf=*0x%x, data_size=0x%llx, nwrite=*0x%x)", fd, offset, buf, data_size, nwrite);
// TODO: use single sys_fs_fcntl syscall
const auto file = idm::get<lv2_file_t>(fd);
if (!file || !(file->flags & CELL_FS_O_ACCMODE))
if (!buf)
{
return CELL_FS_EBADF;
if (nwrite) *nwrite = 0;
return CELL_EFAULT;
}
std::lock_guard<std::mutex> lock(file->mutex);
const auto old_pos = file->file.pos(); file->file.seek(offset);
const auto written = file->file.write(buf.get_ptr(), data_size);
file->file.seek(old_pos);
if (nwrite)
if (fd - 3 > 252)
{
*nwrite = written;
if (nwrite) *nwrite = 0;
return CELL_EBADF;
}
return CELL_OK;
vm::var<lv2_file_op_rw> arg;
arg->_vtable = vm::cast(0xfa8b0000); // Intentionally wrong (provide correct vtable if necessary)
arg->op = 0x8000000b;
arg->fd = fd;
arg->buf = vm::const_ptr_cast<void>(buf);
arg->offset = offset;
arg->size = data_size;
// Call the syscall
const s32 rc = sys_fs_fcntl(fd, 0x8000000b, arg, arg.size());
// Write size written
if (nwrite) *nwrite = rc && rc != CELL_EFSSPECIFIC ? 0 : arg->out_size.value();
return NOT_AN_ERROR(rc ? rc : arg->out_code.value());
}
s32 cellFsStReadInit(u32 fd, vm::cptr<CellFsRingBuffer> ringbuf)
{
cellFs.warning("cellFsStReadInit(fd=%d, ringbuf=*0x%x)", fd, ringbuf);
cellFs.todo("cellFsStReadInit(fd=%d, ringbuf=*0x%x)", fd, ringbuf);
if (ringbuf->copy & ~CELL_FS_ST_COPYLESS)
{
return CELL_FS_EINVAL;
return CELL_EINVAL;
}
if (ringbuf->block_size & 0xfff) // check if a multiple of sector size
{
return CELL_FS_EINVAL;
return CELL_EINVAL;
}
if (ringbuf->ringbuf_size % ringbuf->block_size) // check if a multiple of block_size
{
return CELL_FS_EINVAL;
return CELL_EINVAL;
}
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
if (file->flags & CELL_FS_O_WRONLY)
{
return CELL_FS_EPERM;
return CELL_EPERM;
}
std::lock_guard<std::mutex> lock(file->mutex);
if (!file->st_status.compare_and_swap_test(SSS_NOT_INITIALIZED, SSS_INITIALIZED))
{
return CELL_FS_EBUSY;
}
file->st_ringbuf_size = ringbuf->ringbuf_size;
file->st_block_size = ringbuf->ringbuf_size;
file->st_trans_rate = ringbuf->transfer_rate;
file->st_copyless = ringbuf->copy == CELL_FS_ST_COPYLESS;
const u64 alloc_size = align(file->st_ringbuf_size, file->st_ringbuf_size < 1024 * 1024 ? 64 * 1024 : 1024 * 1024);
file->st_buffer = vm::alloc(static_cast<u32>(alloc_size), vm::main);
file->st_read_size = 0;
file->st_total_read = 0;
file->st_copied = 0;
// TODO
return CELL_OK;
}
s32 cellFsStReadFinish(u32 fd)
{
cellFs.warning("cellFsStReadFinish(fd=%d)", fd);
cellFs.todo("cellFsStReadFinish(fd=%d)", fd);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF; // ???
return CELL_EBADF; // ???
}
std::lock_guard<std::mutex> lock(file->mutex);
if (!file->st_status.compare_and_swap_test(SSS_INITIALIZED, SSS_NOT_INITIALIZED))
{
return CELL_FS_ENXIO;
}
vm::dealloc(file->st_buffer, vm::main);
// TODO
return CELL_OK;
}
s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr<CellFsRingBuffer> ringbuf)
{
cellFs.warning("cellFsStReadGetRingBuf(fd=%d, ringbuf=*0x%x)", fd, ringbuf);
cellFs.todo("cellFsStReadGetRingBuf(fd=%d, ringbuf=*0x%x)", fd, ringbuf);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
if (file->st_status == SSS_NOT_INITIALIZED)
{
return CELL_FS_ENXIO;
}
ringbuf->ringbuf_size = file->st_ringbuf_size;
ringbuf->block_size = file->st_block_size;
ringbuf->transfer_rate = file->st_trans_rate;
ringbuf->copy = file->st_copyless ? CELL_FS_ST_COPYLESS : CELL_FS_ST_COPY;
// TODO
return CELL_OK;
}
s32 cellFsStReadGetStatus(u32 fd, vm::ptr<u64> status)
{
cellFs.warning("cellFsStReadGetRingBuf(fd=%d, status=*0x%x)", fd, status);
cellFs.todo("cellFsStReadGetRingBuf(fd=%d, status=*0x%x)", fd, status);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
switch (file->st_status.load())
{
case SSS_INITIALIZED:
case SSS_STOPPED:
{
*status = CELL_FS_ST_INITIALIZED | CELL_FS_ST_STOP;
break;
}
case SSS_STARTED:
{
*status = CELL_FS_ST_INITIALIZED | CELL_FS_ST_PROGRESS;
break;
}
default:
{
*status = CELL_FS_ST_NOT_INITIALIZED | CELL_FS_ST_STOP;
break;
}
}
// TODO
return CELL_OK;
}
s32 cellFsStReadGetRegid(u32 fd, vm::ptr<u64> regid)
{
cellFs.warning("cellFsStReadGetRingBuf(fd=%d, regid=*0x%x)", fd, regid);
cellFs.todo("cellFsStReadGetRingBuf(fd=%d, regid=*0x%x)", fd, regid);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
if (file->st_status == SSS_NOT_INITIALIZED)
{
return CELL_FS_ENXIO;
}
*regid = file->st_total_read - file->st_copied;
// TODO
return CELL_OK;
}
s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
{
cellFs.warning("cellFsStReadStart(fd=%d, offset=0x%llx, size=0x%llx)", fd, offset, size);
cellFs.todo("cellFsStReadStart(fd=%d, offset=0x%llx, size=0x%llx)", fd, offset, size);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
switch (auto status = file->st_status.compare_and_swap(SSS_INITIALIZED, SSS_STARTED))
{
case SSS_NOT_INITIALIZED:
{
return CELL_FS_ENXIO;
}
case SSS_STARTED:
{
return CELL_FS_EBUSY;
}
}
offset = std::min<u64>(file->file.size(), offset);
size = std::min<u64>(file->file.size() - offset, size);
file->st_read_size = size;
file->st_thread = thread_ctrl::spawn("FS ST Thread", [=]()
{
std::unique_lock<std::mutex> lock(file->mutex);
while (file->st_status == SSS_STARTED && !Emu.IsStopped())
{
// check free space in buffer and available data in stream
if (file->st_total_read - file->st_copied <= file->st_ringbuf_size - file->st_block_size && file->st_total_read < file->st_read_size)
{
// get buffer position
const u32 position = vm::cast(file->st_buffer + file->st_total_read % file->st_ringbuf_size, HERE);
// read data
auto old = file->file.pos();
file->file.seek(offset + file->st_total_read);
auto res = file->file.read(vm::base(position), file->st_block_size);
file->file.seek(old);
// notify
file->st_total_read += res;
file->cv.notify_one();
}
// check callback condition if set
if (file->st_callback.load().func)
{
const u64 available = file->st_total_read - file->st_copied;
if (available >= file->st_callback.load().size)
{
const auto func = file->st_callback.exchange({}).func;
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
{
func(ppu, fd, available);
});
}
}
file->cv.wait_for(lock, 1ms);
}
file->st_status.compare_and_swap(SSS_STOPPED, SSS_INITIALIZED);
file->st_read_size = 0;
file->st_total_read = 0;
file->st_copied = 0;
file->st_callback.store({});
});
// TODO
return CELL_OK;
}
s32 cellFsStReadStop(u32 fd)
{
cellFs.warning("cellFsStReadStop(fd=%d)", fd);
cellFs.todo("cellFsStReadStop(fd=%d)", fd);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
switch (auto status = file->st_status.compare_and_swap(SSS_STARTED, SSS_STOPPED))
{
case SSS_NOT_INITIALIZED:
{
return CELL_FS_ENXIO;
}
case SSS_INITIALIZED:
case SSS_STOPPED:
{
return CELL_OK;
}
}
file->cv.notify_all();
file->st_thread->join();
// TODO
return CELL_OK;
}
s32 cellFsStRead(u32 fd, vm::ptr<u8> buf, u64 size, vm::ptr<u64> rsize)
{
cellFs.warning("cellFsStRead(fd=%d, buf=*0x%x, size=0x%llx, rsize=*0x%x)", fd, buf, size, rsize);
cellFs.todo("cellFsStRead(fd=%d, buf=*0x%x, size=0x%llx, rsize=*0x%x)", fd, buf, size, rsize);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
if (file->st_status == SSS_NOT_INITIALIZED || file->st_copyless)
{
return CELL_FS_ENXIO;
}
// TODO
const u64 copied = file->st_copied;
const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE);
const u64 total_read = file->st_total_read;
const u64 copy_size = (*rsize = std::min<u64>(size, total_read - copied)); // write rsize
// copy data
const u64 first_size = std::min<u64>(copy_size, file->st_ringbuf_size - (position - file->st_buffer));
std::memcpy(buf.get_ptr(), vm::base(position), first_size);
std::memcpy((buf + first_size).get_ptr(), vm::base(file->st_buffer), copy_size - first_size);
// notify
file->st_copied += copy_size;
file->cv.notify_one();
// check end of stream
return total_read < file->st_read_size ? CELL_OK : CELL_FS_ERANGE;
return CELL_OK;
}
s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr<u32> addr, vm::ptr<u64> size)
{
cellFs.warning("cellFsStReadGetCurrentAddr(fd=%d, addr=*0x%x, size=*0x%x)", fd, addr, size);
cellFs.todo("cellFsStReadGetCurrentAddr(fd=%d, addr=*0x%x, size=*0x%x)", fd, addr, size);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
if (file->st_status == SSS_NOT_INITIALIZED || !file->st_copyless)
{
return CELL_FS_ENXIO;
}
// TODO
const u64 copied = file->st_copied;
const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE);
const u64 total_read = file->st_total_read;
if ((*size = std::min<u64>(file->st_ringbuf_size - (position - file->st_buffer), total_read - copied)))
{
*addr = position;
}
else
{
*addr = 0;
}
// check end of stream
return total_read < file->st_read_size ? CELL_OK : CELL_FS_ERANGE;
return CELL_OK;
}
s32 cellFsStReadPutCurrentAddr(u32 fd, vm::ptr<u8> addr, u64 size)
{
cellFs.warning("cellFsStReadPutCurrentAddr(fd=%d, addr=*0x%x, size=0x%llx)", fd, addr, size);
cellFs.todo("cellFsStReadPutCurrentAddr(fd=%d, addr=*0x%x, size=0x%llx)", fd, addr, size);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
if (file->st_status == SSS_NOT_INITIALIZED || !file->st_copyless)
{
return CELL_FS_ENXIO;
}
// TODO
const u64 copied = file->st_copied;
const u64 total_read = file->st_total_read;
// notify
file->st_copied += size;
file->cv.notify_one();
// check end of stream
return total_read < file->st_read_size ? CELL_OK : CELL_FS_ERANGE;
return CELL_OK;
}
s32 cellFsStReadWait(u32 fd, u64 size)
{
cellFs.warning("cellFsStReadWait(fd=%d, size=0x%llx)", fd, size);
cellFs.todo("cellFsStReadWait(fd=%d, size=0x%llx)", fd, size);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
if (file->st_status == SSS_NOT_INITIALIZED)
{
return CELL_FS_ENXIO;
}
std::unique_lock<std::mutex> lock(file->mutex);
// wait for size availability or stream end
while (file->st_total_read - file->st_copied < size && file->st_total_read < file->st_read_size)
{
CHECK_EMU_STATUS;
file->cv.wait_for(lock, 1ms);
}
// TODO
return CELL_OK;
}
s32 cellFsStReadWaitCallback(u32 fd, u64 size, fs_st_cb_t func)
s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptr<void(s32 xfd, u64 xsize)> func)
{
cellFs.warning("cellFsStReadWaitCallback(fd=%d, size=0x%llx, func=*0x%x)", fd, size, func);
cellFs.todo("cellFsStReadWaitCallback(fd=%d, size=0x%llx, func=*0x%x)", fd, size, func);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
if (file->st_status == SSS_NOT_INITIALIZED)
{
return CELL_FS_ENXIO;
}
if (!file->st_callback.compare_and_swap_test({}, { size, func }))
{
return CELL_FS_EIO;
}
// TODO
return CELL_OK;
}
@ -831,7 +650,7 @@ s32 cellFsSdataOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<vo
if (flags != CELL_FS_O_RDONLY)
{
return CELL_FS_EINVAL;
return CELL_EINVAL;
}
return cellFsOpen(path, CELL_FS_O_RDONLY, fd, vm::make_var<be_t<u32>[2]>({ 0x180, 0x10 }), 8);
@ -866,6 +685,12 @@ s32 cellFsSdataOpenByFd(u32 mself_fd, s32 flags, vm::ptr<u32> sdata_fd, u64 offs
using fs_aio_cb_t = vm::ptr<void(vm::ptr<CellFsAio> xaio, s32 error, s32 xid, u64 size)>;
// temporarily
struct lv2_fs_mount_point
{
std::mutex mutex;
};
void fsAio(vm::ptr<CellFsAio> aio, bool write, s32 xid, fs_aio_cb_t func)
{
cellFs.notice("FS AIO Request(%d): fd=%d, offset=0x%llx, buf=*0x%x, size=0x%llx, user_data=0x%llx", xid, aio->fd, aio->offset, aio->buf, aio->size, aio->user_data);
@ -873,21 +698,21 @@ void fsAio(vm::ptr<CellFsAio> aio, bool write, s32 xid, fs_aio_cb_t func)
s32 error = CELL_OK;
u64 result = 0;
const auto file = idm::get<lv2_file_t>(aio->fd);
const auto file = idm::get<lv2_file>(aio->fd);
if (!file || (!write && file->flags & CELL_FS_O_WRONLY) || (write && !(file->flags & CELL_FS_O_ACCMODE)))
{
error = CELL_FS_EBADF;
error = CELL_EBADF;
}
else
{
std::lock_guard<std::mutex> lock(file->mutex);
std::lock_guard<std::mutex> lock(file->mp->mutex);
const auto old_pos = file->file.pos(); file->file.seek(aio->offset);
result = write
? file->file.write(aio->buf.get_ptr(), aio->size)
: file->file.read(aio->buf.get_ptr(), aio->size);
? file->op_write(aio->buf, aio->size)
: file->op_read(aio->buf, aio->size);
file->file.seek(old_pos);
}
@ -949,11 +774,11 @@ s32 cellFsAioWrite(vm::ptr<CellFsAio> aio, vm::ptr<s32> id, fs_aio_cb_t func)
s32 cellFsAioCancel(s32 id)
{
cellFs.warning("cellFsAioCancel(id=%d) -> CELL_FS_EINVAL", id);
cellFs.warning("cellFsAioCancel(id=%d) -> CELL_EINVAL", id);
// TODO: cancelled requests return CELL_FS_ECANCELED through their own callbacks
// TODO: cancelled requests return CELL_ECANCELED through their own callbacks
return CELL_FS_EINVAL;
return CELL_EINVAL;
}
s32 cellFsSetDefaultContainer(u32 id, u32 total_limit)
@ -967,11 +792,11 @@ s32 cellFsSetIoBufferFromDefaultContainer(u32 fd, u32 buffer_size, u32 page_type
{
cellFs.todo("cellFsSetIoBufferFromDefaultContainer(fd=%d, buffer_size=%d, page_type=%d)", fd, buffer_size, page_type);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
return CELL_OK;
@ -1020,6 +845,7 @@ s32 cellFsChangeFileSizeWithoutAllocation()
s32 cellFsAllocateFileAreaWithoutZeroFill(vm::cptr<char> path, u64 size)
{
cellFs.warning("cellFsAllocateFileAreaWithoutZeroFill(path=*0x%x, size=0x%llx)", path, size);
return sys_fs_truncate(path, size);
}
@ -1099,7 +925,7 @@ DECLARE(ppu_module_manager::cellFs)("sys_fs", []()
REG_FUNC(sys_fs, cellFsAllocateFileAreaByFdWithInitialData);
REG_FUNC(sys_fs, cellFsTruncate2);
REG_FUNC(sys_fs, cellFsChangeFileSizeWithoutAllocation);
REG_FUNC(sys_fs, cellFsAllocateFileAreaWithoutZeroFill);
REG_FUNC(sys_fs, cellFsAllocateFileAreaWithoutZeroFill, MFF_FORCED_HLE);
REG_FUNC(sys_fs, cellFsChangeFileSizeByFdWithoutAllocation);
REG_FUNC(sys_fs, cellFsSetDiscReadRetrySetting);
REG_FUNC(sys_fs, cellFsRegisterConversionCallback);

View File

@ -1,6 +1,6 @@
#pragma once
namespace vm { using namespace ps3; }
#include "Emu/Cell/lv2/sys_fs.h"
struct CellFsDirectoryEntry
{
@ -42,7 +42,7 @@ struct CellFsAio
{
be_t<u32> fd;
be_t<u64> offset;
vm::bptr<void> buf;
vm::bptrb<void> buf;
be_t<u64> size;
be_t<u64> user_data;
};

View File

@ -61,7 +61,7 @@ s32 cellGifDecOpen(PMainHandle mainHandle, PPSubHandle subHandle, PSrc src, POpe
if (!file_s) return CELL_GIFDEC_ERROR_OPEN_FILE;
current_subHandle.fileSize = file_s.size();
current_subHandle.fd = idm::make<lv2_file_t>(std::move(file_s), 0, 0);
current_subHandle.fd = idm::make<lv2_file>(src->fileName.get_ptr(), std::move(file_s), 0, 0);
break;
}
}
@ -97,7 +97,7 @@ s32 cellGifDecReadHeader(PMainHandle mainHandle, PSubHandle subHandle, PInfo inf
case CELL_GIFDEC_FILE:
{
auto file = idm::get<lv2_file_t>(fd);
auto file = idm::get<lv2_file>(fd);
file->file.seek(0);
file->file.read(buffer, sizeof(buffer));
break;
@ -181,7 +181,7 @@ s32 cellGifDecDecodeData(PMainHandle mainHandle, PSubHandle subHandle, vm::ptr<u
case CELL_GIFDEC_FILE:
{
auto file = idm::get<lv2_file_t>(fd);
auto file = idm::get<lv2_file>(fd);
file->file.seek(0);
file->file.read(gif.get(), fileSize);
break;
@ -283,7 +283,7 @@ s32 cellGifDecClose(PMainHandle mainHandle, PSubHandle subHandle)
{
cellGifDec.warning("cellGifDecClose(mainHandle=*0x%x, subHandle=*0x%x)", mainHandle, subHandle);
idm::remove<lv2_file_t>(subHandle->fd);
idm::remove<lv2_file>(subHandle->fd);
vm::dealloc(subHandle.addr());

View File

@ -51,7 +51,7 @@ s32 cellJpgDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellJpgDecSrc
if (!file_s) return CELL_JPGDEC_ERROR_OPEN_FILE;
current_subHandle.fileSize = file_s.size();
current_subHandle.fd = idm::make<lv2_file_t>(std::move(file_s), 0, 0);
current_subHandle.fd = idm::make<lv2_file>(src->fileName.get_ptr(), std::move(file_s), 0, 0);
break;
}
}
@ -78,7 +78,7 @@ s32 cellJpgDecClose(u32 mainHandle, u32 subHandle)
return CELL_JPGDEC_ERROR_FATAL;
}
idm::remove<lv2_file_t>(subHandle_data->fd);
idm::remove<lv2_file>(subHandle_data->fd);
idm::remove<CellJpgDecSubHandle>(subHandle);
return CELL_OK;
@ -110,7 +110,7 @@ s32 cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr<CellJpgDecInfo>
case CELL_JPGDEC_FILE:
{
auto file = idm::get<lv2_file_t>(fd);
auto file = idm::get<lv2_file>(fd);
file->file.seek(0);
file->file.read(buffer.get(), fileSize);
break;
@ -189,7 +189,7 @@ s32 cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data, vm::cp
case CELL_JPGDEC_FILE:
{
auto file = idm::get<lv2_file_t>(fd);
auto file = idm::get<lv2_file>(fd);
file->file.seek(0);
file->file.read(jpg.get(), fileSize);
break;

View File

@ -253,8 +253,6 @@ struct CellPamfLpcmInfo
#pragma pack(push, 1) // file data
struct PamfStreamHeader
{
u8 type;
@ -341,7 +339,7 @@ struct PamfStreamHeader
};
};
CHECK_SIZE(PamfStreamHeader, 48);
CHECK_SIZE_ALIGN(PamfStreamHeader, 48, 4);
struct PamfHeader
{
@ -349,25 +347,25 @@ struct PamfHeader
u32 version; //"0041" (is it const?)
be_t<u32> data_offset; //== 2048 >> 11, PAMF headers seem to be always 2048 bytes in size
be_t<u32> data_size; //== ((fileSize - 2048) >> 11)
u64 reserved[8];
u32 reserved[16];
be_t<u32> table_size; //== size of mapping-table
u16 reserved1;
be_t<u16> start_pts_high;
be_t<u32> start_pts_low; //Presentation Time Stamp (start)
be_t<u32, 2> start_pts_low; //Presentation Time Stamp (start)
be_t<u16> end_pts_high;
be_t<u32> end_pts_low; //Presentation Time Stamp (end)
be_t<u32> mux_rate_max; //== 0x01D470 (400 bps per unit, == 48000000 bps)
be_t<u32> mux_rate_min; //== 0x0107AC (?????)
be_t<u32, 2> end_pts_low; //Presentation Time Stamp (end)
be_t<u32, 2> mux_rate_max; //== 0x01D470 (400 bps per unit, == 48000000 bps)
be_t<u32, 2> mux_rate_min; //== 0x0107AC (?????)
u16 reserved2; // ?????
u8 reserved3;
u8 stream_count; //total stream count (reduced to 1 byte)
be_t<u16> unk1; //== 1 (?????)
be_t<u32> table_data_size; //== table_size - 0x20 == 0x14 + (0x30 * total_stream_num) (?????)
be_t<u32, 2> table_data_size; //== table_size - 0x20 == 0x14 + (0x30 * total_stream_num) (?????)
//TODO: check relative offset of stream structs (could be from 0x0c to 0x14, currently 0x14)
be_t<u16> start_pts_high2; //????? (probably same values)
be_t<u32> start_pts_low2; //?????
be_t<u32, 2> start_pts_low2; //?????
be_t<u16> end_pts_high2; //?????
be_t<u32> end_pts_low2; //?????
be_t<u32, 2> end_pts_low2; //?????
be_t<u32> unk2; //== 0x10000 (?????)
be_t<u16> unk3; // ?????
be_t<u16> unk4; // == stream_count
@ -375,6 +373,8 @@ struct PamfHeader
PamfStreamHeader stream_headers[256];
};
CHECK_SIZE_ALIGN(PamfHeader, 136 + sizeof(PamfHeader::stream_headers), 4);
struct PamfEpHeader
{
be_t<u16> value0; //mixed indexN (probably left 2 bits) and nThRefPictureOffset
@ -383,9 +383,7 @@ struct PamfEpHeader
be_t<u32> rpnOffset;
};
CHECK_SIZE(PamfEpHeader, 12);
#pragma pack(pop)
CHECK_SIZE_ALIGN(PamfEpHeader, 12, 4);
// not directly accessed by virtual CPU, fields are unknown
struct CellPamfReader

View File

@ -65,7 +65,7 @@ void pngDecReadBuffer(png_structp png_ptr, png_bytep out, png_size_t length)
if (buffer.file)
{
// Get the file
auto file = idm::get<lv2_file_t>(buffer.fd);
auto file = idm::get<lv2_file>(buffer.fd);
// Read the data
file->file.read(out, length);
@ -364,7 +364,7 @@ s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source,
}
// Get the file descriptor
buffer->fd = idm::make<lv2_file_t>(std::move(file_stream), 0, 0);
buffer->fd = idm::make<lv2_file>(stream->source.fileName.get_ptr(), std::move(file_stream), 0, 0);
// Indicate that we need to read from a file stream
buffer->file = true;
@ -447,7 +447,7 @@ s32 pngDecClose(PPUThread& ppu, PHandle handle, PStream stream)
// Remove the file descriptor, if a file descriptor was used for decoding
if (stream->buffer->file)
{
idm::remove<lv2_file_t>(stream->buffer->fd);
idm::remove<lv2_file>(stream->buffer->fd);
}
// Deallocate the PNG buffer structure used to decode from memory, if we decoded from memory

View File

@ -1,15 +1,48 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_mmapper.h"
#include "sysPrxForUser.h"
namespace vm { using namespace ps3; }
extern logs::channel sysPrxForUser;
void sysPrxForUser_sys_mmapper_init()
s32 sys_mmapper_allocate_memory(u32 size, u64 flags, vm::ptr<u32> mem_id)
{
sysPrxForUser.notice("sys_mmapper_allocate_memory(size=0x%x, flags=0x%llx, mem_id=*0x%x)", size, flags, mem_id);
return sys_mmapper_allocate_shared_memory(0xffff000000000000ull, size, flags, mem_id);
}
s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id)
{
sysPrxForUser.notice("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", size, cid, flags, mem_id);
return sys_mmapper_allocate_shared_memory_from_container(0xffff000000000000ull, size, cid, flags, mem_id);
}
s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags)
{
sysPrxForUser.notice("sys_mmapper_map_memory(addr=0x%x, mem_id=0x%x, flags=0x%llx)", addr, mem_id, flags);
return sys_mmapper_map_shared_memory(addr, mem_id, flags);
}
s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_id)
{
sysPrxForUser.notice("sys_mmapper_unmap_memory(addr=0x%x, mem_id=*0x%x)", addr, mem_id);
return sys_mmapper_unmap_shared_memory(addr, mem_id);
}
s32 sys_mmapper_free_memory(u32 mem_id)
{
sysPrxForUser.notice("sys_mmapper_free_memory(mem_id=0x%x)", mem_id);
return sys_mmapper_free_shared_memory(mem_id);
}
extern void sysPrxForUser_sys_mmapper_init()
{
// TODO: split syscalls and liblv2 functions
REG_FUNC(sysPrxForUser, sys_mmapper_allocate_memory);
REG_FUNC(sysPrxForUser, sys_mmapper_allocate_memory_from_container);
REG_FUNC(sysPrxForUser, sys_mmapper_map_memory);

View File

@ -229,7 +229,7 @@ extern std::string ppu_get_syscall_name(u64 code)
case 353: return "sys_memory_get_user_memory_stat";
case 356: return "sys_memory_allocate_colored";
case 361: return "sys_memory_allocate_from_container_colored";
case 362: return "sys_mmapper_allocate_memory_from_container";
case 362: return "sys_mmapper_allocate_shared_memory_from_container";
case 367: return "sys_uart_initialize";
case 368: return "sys_uart_receive";
case 369: return "sys_uart_send";

View File

@ -333,13 +333,13 @@ std::array<ppu_function_t, 1024> g_ppu_syscall_table
BIND_FUNC(sys_mmapper_allocate_fixed_address), //326 (0x146)
BIND_FUNC(sys_mmapper_enable_page_fault_notification), //327 (0x147)
null_func,//BIND_FUNC(sys_mmapper_...) //328 (0x148)
null_func,//BIND_FUNC(sys_mmapper_free_shared_memory) //329 (0x149)
BIND_FUNC(sys_mmapper_free_shared_memory), //329 (0x149)
BIND_FUNC(sys_mmapper_allocate_address), //330 (0x14A)
BIND_FUNC(sys_mmapper_free_address), //331 (0x14B)
null_func,//BIND_FUNC(sys_mmapper_allocate_shared_memory)//332(0x14C)
BIND_FUNC(sys_mmapper_allocate_shared_memory), //332 (0x14C)
null_func,//BIND_FUNC(sys_mmapper_set_shared_memory_flag)//333(0x14D)
null_func,//BIND_FUNC(sys_mmapper_map_shared_memory) //334 (0x14E)
null_func,//BIND_FUNC(sys_mmapper_unmap_shared_memory) //335 (0x14F)
BIND_FUNC(sys_mmapper_map_shared_memory), //334 (0x14E)
BIND_FUNC(sys_mmapper_unmap_shared_memory), //335 (0x14F)
BIND_FUNC(sys_mmapper_change_address_access_right), //336 (0x150)
BIND_FUNC(sys_mmapper_search_and_map), //337 (0x151)
null_func,//BIND_FUNC(sys_mmapper_get_shared_memory_attribute) //338 (0x152)
@ -366,7 +366,7 @@ std::array<ppu_function_t, 1024> g_ppu_syscall_table
null_func,//BIND_FUNC(sys_memory_...) //359 (0x167)
null_func,//BIND_FUNC(sys_memory_...) //360 (0x168)
null_func,//BIND_FUNC(sys_memory_allocate_from_container_colored) //361 (0x169)
null_func,//BIND_FUNC(sys_mmapper_allocate_memory_from_container) //362 (0x16A)
BIND_FUNC(sys_mmapper_allocate_shared_memory_from_container),//362 (0x16A)
null_func,//BIND_FUNC(sys_mmapper_...) //363 (0x16B)
null_func,//BIND_FUNC(sys_mmapper_...) //364 (0x16C)
null_func, //365 (0x16D) UNS

View File

@ -1,24 +1,58 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_fs.h"
#include <mutex>
#include "Emu/VFS.h"
#include "Utilities/StrUtil.h"
#include <cerrno>
namespace vm { using namespace ps3; }
logs::channel sys_fs("sys_fs", logs::level::notice);
s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6)
struct lv2_fs_mount_point
{
std::mutex mutex;
};
lv2_fs_mount_point g_mp_sys_dev_hdd0;
lv2_fs_mount_point g_mp_sys_dev_hdd1;
lv2_fs_mount_point g_mp_sys_dev_usb;
lv2_fs_mount_point g_mp_sys_dev_bdvd;
lv2_fs_mount_point g_mp_sys_app_home;
lv2_fs_mount_point g_mp_sys_host_root;
lv2_fs_mount_point* lv2_fs_object::get_mp(const char* filename)
{
// TODO
return &g_mp_sys_dev_hdd0;
}
u64 lv2_file::op_read(vm::ps3::ptr<void> buf, u64 size)
{
// Copy data from intermediate buffer (avoid passing vm pointer to a native API)
std::unique_ptr<u8[]> local_buf(new u8[size]);
const u64 result = file.read(local_buf.get(), size);
std::memcpy(buf.get_ptr(), local_buf.get(), result);
return result;
}
u64 lv2_file::op_write(vm::ps3::cptr<void> buf, u64 size)
{
// Copy data to intermediate buffer (avoid passing vm pointer to a native API)
std::unique_ptr<u8[]> local_buf(new u8[size]);
std::memcpy(local_buf.get(), buf.get_ptr(), size);
return file.write(local_buf.get(), size);
}
ppu_error_code sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6)
{
sys_fs.todo("sys_fs_test(arg1=0x%x, arg2=0x%x, arg3=*0x%x, arg4=0x%x, arg5=*0x%x, arg6=0x%x) -> CELL_OK", arg1, arg2, arg3, arg4, arg5, arg6);
return CELL_OK;
}
s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size)
ppu_error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size)
{
sys_fs.warning("sys_fs_open(path=*0x%x, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size);
sys_fs.warning("*** path = '%s'", path.get_ptr());
@ -26,14 +60,15 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
if (!path[0])
{
sys_fs.error("sys_fs_open('%s') failed: path is invalid", path.get_ptr());
return CELL_FS_EINVAL;
return CELL_EINVAL;
}
const std::string& local_path = vfs::get(path.get_ptr());
if (local_path.empty())
{
sys_fs.error("sys_fs_open('%s') failed: device not mounted", path.get_ptr());
return CELL_FS_ENOTMOUNTED;
return CELL_ENOTMOUNTED;
}
// TODO: other checks for path
@ -41,7 +76,7 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
if (fs::is_dir(local_path))
{
sys_fs.error("sys_fs_open('%s') failed: path is a directory", path.get_ptr());
return CELL_FS_EISDIR;
return CELL_EISDIR;
}
bitset_t<fs::open_mode> open_mode{};
@ -103,18 +138,18 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
if (open_mode & fs::excl)
{
return CELL_FS_EEXIST; // approximation
return CELL_EEXIST; // approximation
}
return CELL_FS_ENOENT;
return CELL_ENOENT;
}
const auto _file = idm::make_ptr<lv2_file_t>(std::move(file), mode, flags);
const auto _file = idm::make_ptr<lv2_file>(path.get_ptr(), std::move(file), mode, flags);
if (!_file)
{
// out of file descriptors
return CELL_FS_EMFILE;
return CELL_EMFILE;
}
*fd = _file->id;
@ -122,7 +157,7 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
return CELL_OK;
}
s32 sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
ppu_error_code sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
{
sys_fs.trace("sys_fs_read(fd=%d, buf=*0x%x, nbytes=0x%llx, nread=*0x%x)", fd, buf, nbytes, nread);
@ -131,80 +166,93 @@ s32 sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
return CELL_EFAULT;
}
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file || file->flags & CELL_FS_O_WRONLY)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
std::lock_guard<std::mutex> lock(file->mutex);
std::lock_guard<std::mutex> lock(file->mp->mutex);
std::unique_ptr<u8[]> local_buf(new u8[nbytes]);
std::memcpy(buf.get_ptr(), local_buf.get(), *nread = file->file.read(local_buf.get(), nbytes));
*nread = file->op_read(buf, nbytes);
return CELL_OK;
}
s32 sys_fs_write(u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
ppu_error_code sys_fs_write(u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
{
sys_fs.trace("sys_fs_write(fd=%d, buf=*0x%x, nbytes=0x%llx, nwrite=*0x%x)", fd, buf, nbytes, nwrite);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file || !(file->flags & CELL_FS_O_ACCMODE))
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
// TODO: return CELL_FS_EBUSY if locked by stream
// TODO: return CELL_EBUSY if locked by stream
std::lock_guard<std::mutex> lock(file->mutex);
std::lock_guard<std::mutex> lock(file->mp->mutex);
std::unique_ptr<u8[]> local_buf(new u8[nbytes]);
std::memcpy(local_buf.get(), buf.get_ptr(), nbytes);
*nwrite = file->file.write(local_buf.get(), nbytes);
*nwrite = file->op_write(buf, nbytes);
return CELL_OK;
}
s32 sys_fs_close(u32 fd)
ppu_error_code sys_fs_close(u32 fd)
{
sys_fs.trace("sys_fs_close(fd=%d)", fd);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
// TODO: return CELL_FS_EBUSY if locked
// TODO: return CELL_EBUSY if locked
idm::remove<lv2_file_t>(fd);
idm::remove<lv2_file>(fd);
return CELL_OK;
}
s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
ppu_error_code sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
{
sys_fs.warning("sys_fs_opendir(path=*0x%x, fd=*0x%x)", path, fd);
sys_fs.warning("*** path = '%s'", path.get_ptr());
fs::dir dir(vfs::get(path.get_ptr()));
const std::string& local_path = vfs::get(path.get_ptr());
if (local_path.empty())
{
sys_fs.error("sys_fs_opendir('%s') failed: device not mounted", path.get_ptr());
return CELL_ENOTMOUNTED;
}
// TODO: other checks for path
if (fs::is_file(local_path))
{
sys_fs.error("sys_fs_opendir('%s') failed: path is a file", path.get_ptr());
return CELL_ENOTDIR;
}
fs::dir dir(local_path);
if (!dir)
{
sys_fs.error("sys_fs_opendir('%s'): failed to open directory", path.get_ptr());
return CELL_FS_ENOENT;
return CELL_ENOENT;
}
const auto _dir = idm::make_ptr<lv2_dir_t>(std::move(dir));
const auto _dir = idm::make_ptr<lv2_dir>(path.get_ptr(), std::move(dir));
if (!_dir)
{
// out of file descriptors
return CELL_FS_EMFILE;
return CELL_EMFILE;
}
*fd = _dir->id;
@ -212,15 +260,15 @@ s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
return CELL_OK;
}
s32 sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
ppu_error_code sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
{
sys_fs.warning("sys_fs_readdir(fd=%d, dir=*0x%x, nread=*0x%x)", fd, dir, nread);
const auto directory = idm::get<lv2_dir_t>(fd);
const auto directory = idm::get<lv2_dir>(fd);
if (!directory)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
fs::dir_entry info;
@ -240,23 +288,23 @@ s32 sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
return CELL_OK;
}
s32 sys_fs_closedir(u32 fd)
ppu_error_code sys_fs_closedir(u32 fd)
{
sys_fs.trace("sys_fs_closedir(fd=%d)", fd);
const auto directory = idm::get<lv2_dir_t>(fd);
const auto directory = idm::get<lv2_dir>(fd);
if (!directory)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
idm::remove<lv2_dir_t>(fd);
idm::remove<lv2_dir>(fd);
return CELL_OK;
}
s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
ppu_error_code sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
{
sys_fs.warning("sys_fs_stat(path=*0x%x, sb=*0x%x)", path, sb);
sys_fs.warning("*** path = '%s'", path.get_ptr());
@ -266,7 +314,7 @@ s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
if (local_path.empty())
{
sys_fs.warning("sys_fs_stat('%s') failed: not mounted", path.get_ptr());
return CELL_FS_ENOTMOUNTED;
return CELL_ENOTMOUNTED;
}
fs::stat_t info;
@ -274,7 +322,7 @@ s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
if (!fs::stat(local_path, info))
{
sys_fs.error("sys_fs_stat('%s') failed: not found", path.get_ptr());
return CELL_FS_ENOENT;
return CELL_ENOENT;
}
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
@ -289,18 +337,18 @@ s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
return CELL_OK;
}
s32 sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb)
ppu_error_code sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb)
{
sys_fs.warning("sys_fs_fstat(fd=%d, sb=*0x%x)", fd, sb);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
std::lock_guard<std::mutex> lock(file->mutex);
std::lock_guard<std::mutex> lock(file->mp->mutex);
const fs::stat_t& info = file->file.stat();
@ -316,7 +364,7 @@ s32 sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb)
return CELL_OK;
}
s32 sys_fs_mkdir(vm::cptr<char> path, s32 mode)
ppu_error_code sys_fs_mkdir(vm::cptr<char> path, s32 mode)
{
sys_fs.warning("sys_fs_mkdir(path=*0x%x, mode=%#o)", path, mode);
sys_fs.warning("*** path = '%s'", path.get_ptr());
@ -325,19 +373,19 @@ s32 sys_fs_mkdir(vm::cptr<char> path, s32 mode)
if (fs::is_dir(local_path))
{
return CELL_FS_EEXIST;
return CELL_EEXIST;
}
if (!fs::create_path(local_path))
{
return CELL_FS_EIO; // ???
return CELL_EIO; // ???
}
sys_fs.notice("sys_fs_mkdir(): directory '%s' created", path.get_ptr());
return CELL_OK;
}
s32 sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
ppu_error_code sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
{
sys_fs.warning("sys_fs_rename(from=*0x%x, to=*0x%x)", from, to);
sys_fs.warning("*** from = '%s'", from.get_ptr());
@ -345,14 +393,14 @@ s32 sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr())))
{
return CELL_FS_ENOENT; // ???
return CELL_ENOENT; // ???
}
sys_fs.notice("sys_fs_rename(): '%s' renamed to '%s'", from.get_ptr(), to.get_ptr());
return CELL_OK;
}
s32 sys_fs_rmdir(vm::cptr<char> path)
ppu_error_code sys_fs_rmdir(vm::cptr<char> path)
{
sys_fs.warning("sys_fs_rmdir(path=*0x%x)", path);
sys_fs.warning("*** path = '%s'", path.get_ptr());
@ -361,18 +409,18 @@ s32 sys_fs_rmdir(vm::cptr<char> path)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return CELL_FS_ENOENT;
case fs::error::noent: return CELL_ENOENT;
default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error);
}
return CELL_FS_EIO; // ???
return CELL_EIO; // ???
}
sys_fs.notice("sys_fs_rmdir(): directory '%s' removed", path.get_ptr());
return CELL_OK;
}
s32 sys_fs_unlink(vm::cptr<char> path)
ppu_error_code sys_fs_unlink(vm::cptr<char> path)
{
sys_fs.warning("sys_fs_unlink(path=*0x%x)", path);
sys_fs.warning("*** path = '%s'", path.get_ptr());
@ -381,57 +429,107 @@ s32 sys_fs_unlink(vm::cptr<char> path)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return CELL_FS_ENOENT;
case fs::error::noent: return CELL_ENOENT;
default: sys_fs.error("sys_fs_unlink(): unknown error %d", error);
}
return CELL_FS_EIO; // ???
return CELL_EIO; // ???
}
sys_fs.notice("sys_fs_unlink(): file '%s' deleted", path.get_ptr());
return CELL_OK;
}
s32 sys_fs_fcntl(u32 fd, s32 flags, u32 addr, u32 arg4, u32 arg5, u32 arg6)
ppu_error_code sys_fs_fcntl(u32 fd, u32 op, vm::ptr<void> _arg, u32 _size)
{
sys_fs.todo("sys_fs_fcntl(fd=0x%x, flags=0x%x, addr=*0x%x, arg4=0x%x, arg5=0x%x, arg6=0x%x) -> CELL_OK", fd, flags, addr, arg4, arg5, arg6);
sys_fs.trace("sys_fs_fcntl(fd=%d, op=0x%x, arg=*0x%x, size=0x%x)", fd, op, _arg, _size);
switch (op)
{
case 0x8000000A: // Read with offset
case 0x8000000B: // Write with offset
{
const auto arg = vm::static_ptr_cast<lv2_file_op_rw>(_arg);
if (_size < arg.size())
{
return CELL_EINVAL;
}
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_EBADF;
}
if (op == 0x8000000A && file->flags & CELL_FS_O_WRONLY)
{
return CELL_EBADF;
}
if (op == 0x8000000B && !(file->flags & CELL_FS_O_ACCMODE))
{
return CELL_EBADF;
}
std::lock_guard<std::mutex> lock(file->mp->mutex);
const u64 old_pos = file->file.pos();
const u64 new_pos = file->file.seek(arg->offset);
arg->out_size = op == 0x8000000A
? file->op_read(arg->buf, arg->size)
: file->op_write(arg->buf, arg->size);
VERIFY(old_pos == file->file.seek(old_pos));
arg->out_code = CELL_OK;
break;
}
default:
{
sys_fs.todo("sys_fs_fcntl(): Unknown operation 0x%08x (fd=%d, arg=*0x%x, size=0x%x)", op, fd, _arg, _size);
}
}
return CELL_OK;
}
s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
ppu_error_code sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
{
sys_fs.trace("sys_fs_lseek(fd=%d, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos);
if (whence >= 3)
{
sys_fs.error("sys_fs_lseek(): invalid seek whence (%d)", whence);
return CELL_FS_EINVAL;
return CELL_EINVAL;
}
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
std::lock_guard<std::mutex> lock(file->mutex);
std::lock_guard<std::mutex> lock(file->mp->mutex);
*pos = file->file.seek(offset, static_cast<fs::seek_mode>(whence));
return CELL_OK;
}
s32 sys_fs_fget_block_size(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4, vm::ptr<u64> arg5)
ppu_error_code sys_fs_fget_block_size(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4, vm::ptr<u64> arg5)
{
sys_fs.todo("sys_fs_fget_block_size(fd=%d, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x, arg5=*0x%x)", fd, sector_size, block_size, arg4, arg5);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file)
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
*sector_size = 4096; // ?
@ -440,7 +538,7 @@ s32 sys_fs_fget_block_size(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_
return CELL_OK;
}
s32 sys_fs_get_block_size(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4)
ppu_error_code sys_fs_get_block_size(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4)
{
sys_fs.todo("sys_fs_get_block_size(path=*0x%x, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x, arg5=*0x%x)", path, sector_size, block_size, arg4);
sys_fs.todo("*** path = '%s'", path.get_ptr());
@ -451,7 +549,7 @@ s32 sys_fs_get_block_size(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr
return CELL_OK;
}
s32 sys_fs_truncate(vm::cptr<char> path, u64 size)
ppu_error_code sys_fs_truncate(vm::cptr<char> path, u64 size)
{
sys_fs.warning("sys_fs_truncate(path=*0x%x, size=0x%llx)", path, size);
sys_fs.warning("*** path = '%s'", path.get_ptr());
@ -460,28 +558,28 @@ s32 sys_fs_truncate(vm::cptr<char> path, u64 size)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return CELL_FS_ENOENT;
case fs::error::noent: return CELL_ENOENT;
default: sys_fs.error("sys_fs_truncate(): unknown error %d", error);
}
return CELL_FS_EIO; // ???
return CELL_EIO; // ???
}
return CELL_OK;
}
s32 sys_fs_ftruncate(u32 fd, u64 size)
ppu_error_code sys_fs_ftruncate(u32 fd, u64 size)
{
sys_fs.warning("sys_fs_ftruncate(fd=%d, size=0x%llx)", fd, size);
const auto file = idm::get<lv2_file_t>(fd);
const auto file = idm::get<lv2_file>(fd);
if (!file || !(file->flags & CELL_FS_O_ACCMODE))
{
return CELL_FS_EBADF;
return CELL_EBADF;
}
std::lock_guard<std::mutex> lock(file->mutex);
std::lock_guard<std::mutex> lock(file->mp->mutex);
if (!file->file.trunc(size))
{
@ -491,13 +589,13 @@ s32 sys_fs_ftruncate(u32 fd, u64 size)
default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error);
}
return CELL_FS_EIO; // ???
return CELL_EIO; // ???
}
return CELL_OK;
}
s32 sys_fs_chmod(vm::cptr<char> path, s32 mode)
ppu_error_code sys_fs_chmod(vm::cptr<char> path, s32 mode)
{
sys_fs.todo("sys_fs_chmod(path=*0x%x, mode=%#o) -> CELL_OK", path, mode);
sys_fs.todo("*** path = '%s'", path.get_ptr());

View File

@ -1,69 +1,8 @@
#pragma once
#include "Utilities/Thread.h"
#include <mutex>
#include <condition_variable>
namespace vm { using namespace ps3; }
#pragma pack(push, 4)
// Error Codes
enum : s32
{
CELL_FS_EDOM = CELL_EDOM,
CELL_FS_EFAULT = CELL_EFAULT,
CELL_FS_EFBIG = CELL_EFBIG,
CELL_FS_EFPOS = CELL_EFPOS,
CELL_FS_EMLINK = CELL_EMLINK,
CELL_FS_ENFILE = CELL_ENFILE,
CELL_FS_ENOENT = CELL_ENOENT,
CELL_FS_ENOSPC = CELL_ENOSPC,
CELL_FS_ENOTTY = CELL_ENOTTY,
CELL_FS_EPIPE = CELL_EPIPE,
CELL_FS_ERANGE = CELL_ERANGE,
CELL_FS_EROFS = CELL_EROFS,
CELL_FS_ESPIPE = CELL_ESPIPE,
CELL_FS_E2BIG = CELL_E2BIG,
CELL_FS_EACCES = CELL_EACCES,
CELL_FS_EAGAIN = CELL_EAGAIN,
CELL_FS_EBADF = CELL_EBADF,
CELL_FS_EBUSY = CELL_EBUSY,
//CELL_FS_ECHILD = CELL_ECHILD,
CELL_FS_EEXIST = CELL_EEXIST,
CELL_FS_EINTR = CELL_EINTR,
CELL_FS_EINVAL = CELL_EINVAL,
CELL_FS_EIO = CELL_EIO,
CELL_FS_EISDIR = CELL_EISDIR,
CELL_FS_EMFILE = CELL_EMFILE,
CELL_FS_ENODEV = CELL_ENODEV,
CELL_FS_ENOEXEC = CELL_ENOEXEC,
CELL_FS_ENOMEM = CELL_ENOMEM,
CELL_FS_ENOTDIR = CELL_ENOTDIR,
CELL_FS_ENXIO = CELL_ENXIO,
CELL_FS_EPERM = CELL_EPERM,
CELL_FS_ESRCH = CELL_ESRCH,
CELL_FS_EXDEV = CELL_EXDEV,
CELL_FS_EBADMSG = CELL_EBADMSG,
CELL_FS_ECANCELED = CELL_ECANCELED,
CELL_FS_EDEADLK = CELL_EDEADLK,
CELL_FS_EILSEQ = CELL_EILSEQ,
CELL_FS_EINPROGRESS = CELL_EINPROGRESS,
CELL_FS_EMSGSIZE = CELL_EMSGSIZE,
CELL_FS_ENAMETOOLONG = CELL_ENAMETOOLONG,
CELL_FS_ENOLCK = CELL_ENOLCK,
CELL_FS_ENOSYS = CELL_ENOSYS,
CELL_FS_ENOTEMPTY = CELL_ENOTEMPTY,
CELL_FS_ENOTSUP = CELL_ENOTSUP,
CELL_FS_ETIMEDOUT = CELL_ETIMEDOUT,
CELL_FS_EFSSPECIFIC = CELL_EFSSPECIFIC,
CELL_FS_EOVERFLOW = CELL_EOVERFLOW,
CELL_FS_ENOTMOUNTED = CELL_ENOTMOUNTED,
CELL_FS_ENOTMSELF = CELL_ENOTMSELF,
CELL_FS_ENOTSDATA = CELL_ENOTSDATA,
CELL_FS_EAUTHFATAL = CELL_EAUTHFATAL,
};
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/IdManager.h"
// Open Flags
enum : s32
@ -94,7 +33,7 @@ enum : s32
CELL_FS_MAX_MP_LENGTH = 31,
};
enum CellFsMode : s32
enum : s32
{
CELL_FS_S_IFMT = 0170000,
CELL_FS_S_IFDIR = 0040000, // directory
@ -136,113 +75,134 @@ struct CellFsStat
be_t<s32> mode;
be_t<s32> uid;
be_t<s32> gid;
be_t<s64> atime;
be_t<s64> mtime;
be_t<s64> ctime;
be_t<u64> size;
be_t<u64> blksize;
be_t<s64, 4> atime;
be_t<s64, 4> mtime;
be_t<s64, 4> ctime;
be_t<u64, 4> size;
be_t<u64, 4> blksize;
};
CHECK_SIZE_ALIGN(CellFsStat, 52, 4);
struct CellFsUtimbuf
{
be_t<s64> actime;
be_t<s64> modtime;
be_t<s64, 4> actime;
be_t<s64, 4> modtime;
};
#pragma pack(pop)
CHECK_SIZE_ALIGN(CellFsUtimbuf, 16, 4);
// Stream Support Status (st_status)
enum : u32
struct lv2_fs_mount_point;
struct lv2_fs_object
{
SSS_NOT_INITIALIZED = 0,
SSS_INITIALIZED,
SSS_STARTED,
SSS_STOPPED,
};
using fs_st_cb_t = vm::ptr<void(u32 xfd, u64 xsize)>;
struct alignas(16) fs_st_cb_rec_t
{
u64 size;
fs_st_cb_t func;
u32 pad;
};
struct lv2_fs_object_t
{
using id_base = lv2_fs_object_t;
// ID Manager setups
using id_base = lv2_fs_object;
static constexpr u32 id_min = 3;
static constexpr u32 id_max = 255;
const id_value<> id{};
// Mount Point
const std::add_pointer_t<lv2_fs_mount_point> mp;
lv2_fs_object(lv2_fs_mount_point* mp)
: mp(mp)
{
}
static lv2_fs_mount_point* get_mp(const char* filename);
};
struct lv2_file_t : lv2_fs_object_t
struct lv2_file : lv2_fs_object
{
const fs::file file;
const s32 mode;
const s32 flags;
std::mutex mutex;
std::condition_variable cv;
atomic_t<u32> st_status;
u64 st_ringbuf_size;
u64 st_block_size;
u64 st_trans_rate;
bool st_copyless;
std::shared_ptr<thread_ctrl> st_thread;
u32 st_buffer;
u64 st_read_size;
atomic_t<u64> st_total_read;
atomic_t<u64> st_copied;
atomic_t<fs_st_cb_rec_t> st_callback;
lv2_file_t(fs::file file, s32 mode, s32 flags)
: file(std::move(file))
lv2_file(const char* filename, fs::file&& file, s32 mode, s32 flags)
: lv2_fs_object(lv2_fs_object::get_mp(filename))
, file(std::move(file))
, mode(mode)
, flags(flags)
, st_status(SSS_NOT_INITIALIZED)
, st_callback(fs_st_cb_rec_t{})
{
}
// File reading with intermediate buffer
u64 op_read(vm::ps3::ptr<void> buf, u64 size);
// File writing with intermediate buffer
u64 op_write(vm::ps3::cptr<void> buf, u64 size);
};
struct lv2_dir_t : lv2_fs_object_t
struct lv2_dir : lv2_fs_object
{
const fs::dir dir;
lv2_dir_t(fs::dir dir)
: dir(std::move(dir))
lv2_dir(const char* filename, fs::dir&& dir)
: lv2_fs_object(lv2_fs_object::get_mp(filename))
, dir(std::move(dir))
{
}
};
// sys_fs_fcntl arg base class (left empty for PODness)
struct lv2_file_op
{
};
namespace vtable
{
struct lv2_file_op
{
// Speculation
vm::bptrb<vm::ptrb<void>(vm::ptrb<lv2_file_op>)> get_data;
vm::bptrb<u32(vm::ptrb<lv2_file_op>)> get_size;
vm::bptrb<void(vm::ptrb<lv2_file_op>)> _dtor1;
vm::bptrb<void(vm::ptrb<lv2_file_op>)> _dtor2;
};
}
// sys_fs_fcntl: read with offset, write with offset
struct lv2_file_op_rw : lv2_file_op
{
vm::bptrb<vtable::lv2_file_op> _vtable;
be_t<u32> op;
be_t<u32> _x8; // ???
be_t<u32> _xc; // ???
be_t<u32> fd; // File descriptor (3..255)
vm::bptrb<void> buf; // Buffer for data
be_t<u64> offset; // File offset
be_t<u64> size; // Access size
be_t<s32> out_code; // Op result
be_t<u64> out_size; // Size processed
};
CHECK_SIZE(lv2_file_op_rw, 0x38);
// SysCalls
s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6);
s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size);
s32 sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread);
s32 sys_fs_write(u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite);
s32 sys_fs_close(u32 fd);
s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd);
s32 sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread);
s32 sys_fs_closedir(u32 fd);
s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb);
s32 sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb);
s32 sys_fs_mkdir(vm::cptr<char> path, s32 mode);
s32 sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to);
s32 sys_fs_rmdir(vm::cptr<char> path);
s32 sys_fs_unlink(vm::cptr<char> path);
s32 sys_fs_fcntl(u32 fd, s32 flags, u32 addr, u32 arg4, u32 arg5, u32 arg6);
s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos);
s32 sys_fs_fget_block_size(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4, vm::ptr<u64> arg5);
s32 sys_fs_get_block_size(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4);
s32 sys_fs_truncate(vm::cptr<char> path, u64 size);
s32 sys_fs_ftruncate(u32 fd, u64 size);
s32 sys_fs_chmod(vm::cptr<char> path, s32 mode);
ppu_error_code sys_fs_test(u32 arg1, u32 arg2, vm::ps3::ptr<u32> arg3, u32 arg4, vm::ps3::ptr<char> arg5, u32 arg6);
ppu_error_code sys_fs_open(vm::ps3::cptr<char> path, s32 flags, vm::ps3::ptr<u32> fd, s32 mode, vm::ps3::cptr<void> arg, u64 size);
ppu_error_code sys_fs_read(u32 fd, vm::ps3::ptr<void> buf, u64 nbytes, vm::ps3::ptr<u64> nread);
ppu_error_code sys_fs_write(u32 fd, vm::ps3::cptr<void> buf, u64 nbytes, vm::ps3::ptr<u64> nwrite);
ppu_error_code sys_fs_close(u32 fd);
ppu_error_code sys_fs_opendir(vm::ps3::cptr<char> path, vm::ps3::ptr<u32> fd);
ppu_error_code sys_fs_readdir(u32 fd, vm::ps3::ptr<CellFsDirent> dir, vm::ps3::ptr<u64> nread);
ppu_error_code sys_fs_closedir(u32 fd);
ppu_error_code sys_fs_stat(vm::ps3::cptr<char> path, vm::ps3::ptr<CellFsStat> sb);
ppu_error_code sys_fs_fstat(u32 fd, vm::ps3::ptr<CellFsStat> sb);
ppu_error_code sys_fs_mkdir(vm::ps3::cptr<char> path, s32 mode);
ppu_error_code sys_fs_rename(vm::ps3::cptr<char> from, vm::ps3::cptr<char> to);
ppu_error_code sys_fs_rmdir(vm::ps3::cptr<char> path);
ppu_error_code sys_fs_unlink(vm::ps3::cptr<char> path);
ppu_error_code sys_fs_fcntl(u32 fd, u32 op, vm::ps3::ptr<void> arg, u32 size);
ppu_error_code sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ps3::ptr<u64> pos);
ppu_error_code sys_fs_fget_block_size(u32 fd, vm::ps3::ptr<u64> sector_size, vm::ps3::ptr<u64> block_size, vm::ps3::ptr<u64> arg4, vm::ps3::ptr<u64> arg5);
ppu_error_code sys_fs_get_block_size(vm::ps3::cptr<char> path, vm::ps3::ptr<u64> sector_size, vm::ps3::ptr<u64> block_size, vm::ps3::ptr<u64> arg4);
ppu_error_code sys_fs_truncate(vm::ps3::cptr<char> path, u64 size);
ppu_error_code sys_fs_ftruncate(u32 fd, u64 size);
ppu_error_code sys_fs_chmod(vm::ps3::cptr<char> path, s32 mode);

View File

@ -1,21 +1,16 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_memory.h"
namespace vm { using namespace ps3; }
logs::channel sys_memory("sys_memory", logs::level::notice);
s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr)
ppu_error_code sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr)
{
sys_memory.warning("sys_memory_allocate(size=0x%x, flags=0x%llx, alloc_addr=*0x%x)", size, flags, alloc_addr);
LV2_LOCK;
// Check allocation size
switch(flags)
switch (flags)
{
case SYS_MEMORY_PAGE_SIZE_1M:
{
@ -43,36 +38,24 @@ s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr)
}
}
// Allocate memory
const u32 addr =
flags == SYS_MEMORY_PAGE_SIZE_1M ? vm::alloc(size, vm::user_space, 0x100000) :
flags == SYS_MEMORY_PAGE_SIZE_64K ? vm::alloc(size, vm::user_space, 0x10000) :
throw EXCEPTION("Unexpected flags");
// Get "default" memory container
const auto dct = fxm::get_always<lv2_memory_container>();
if (!addr)
// Try to get "physical memory"
if (!dct->take(size))
{
return CELL_ENOMEM;
}
// Write back the start address of the allocated area
*alloc_addr = addr;
// Allocate memory, write back the start address of the allocated area
VERIFY(*alloc_addr = vm::alloc(size, vm::user_space, flags == SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000));
return CELL_OK;
}
s32 sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr)
ppu_error_code sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr)
{
sys_memory.warning("sys_memory_allocate_from_container(size=0x%x, cid=0x%x, flags=0x%llx, alloc_addr=*0x%x)", size, cid, flags, alloc_addr);
LV2_LOCK;
// Check if this container ID is valid
const auto ct = idm::get<lv2_memory_container_t>(cid);
if (!ct)
{
return CELL_ESRCH;
}
// Check allocation size
switch (flags)
@ -103,89 +86,69 @@ s32 sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32
}
}
if (ct->used > ct->size)
ppu_error_code result{};
const auto ct = idm::get<lv2_memory_container>(cid, [&](u32, lv2_memory_container& ct)
{
throw EXCEPTION("Unexpected amount of memory taken (0x%x, size=0x%x)", ct->used.load(), ct->size);
// Try to get "physical memory"
if (!ct.take(size))
{
result = CELL_ENOMEM;
return_ false;
}
return_ true;
});
if (!ct && !result)
{
return CELL_ESRCH;
}
// Check memory availability
if (size > ct->size - ct->used)
if (!ct)
{
return CELL_ENOMEM;
return result;
}
const auto area = vm::get(vm::user_space);
// Return "physical" memory required for allocation
area->used -= size;
// Allocate memory
const u32 addr =
flags == SYS_MEMORY_PAGE_SIZE_1M ? area->alloc(size, 0x100000) :
flags == SYS_MEMORY_PAGE_SIZE_64K ? area->alloc(size, 0x10000) :
throw EXCEPTION("Unexpected flags");
if (!addr)
{
throw EXCEPTION("Memory not allocated (ct=0x%x, size=0x%x)", cid, size);
}
// Store the address and size in the container
ct->allocs.emplace(addr, size);
ct->used += size;
// Write back the start address of the allocated area.
*alloc_addr = addr;
// Allocate memory, write back the start address of the allocated area, use cid as the supplementary info
VERIFY(*alloc_addr = vm::alloc(size, vm::user_space, flags == SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000, cid));
return CELL_OK;
}
s32 sys_memory_free(u32 addr)
ppu_error_code sys_memory_free(u32 addr)
{
sys_memory.warning("sys_memory_free(addr=0x%x)", addr);
LV2_LOCK;
const auto area = vm::get(vm::user_space);
// Check all memory containers
const auto ct = idm::select<lv2_memory_container_t>([&](u32, lv2_memory_container_t& ct)
{
return ct.allocs.count(addr) != 0;
});
VERIFY(area);
if (ct)
{
const u32 size = ct->allocs.at(addr);
// Deallocate memory
u32 cid, size = area->dealloc(addr, &cid);
if (!area->dealloc(addr))
{
throw EXCEPTION("Memory not deallocated (cid=0x%x, addr=0x%x, size=0x%x)", ct->id, addr, size);
}
ct->allocs.erase(addr);
// Return "memory"
ct->used -= size;
area->used += size;
return CELL_OK;
}
if (!area->dealloc(addr))
if (!size)
{
return CELL_EINVAL;
}
// Return "physical memory"
if (cid == 0)
{
fxm::get<lv2_memory_container>()->used -= size;
}
else if (const auto ct = idm::get<lv2_memory_container>(cid))
{
ct->used -= size;
}
return CELL_OK;
}
s32 sys_memory_get_page_attribute(u32 addr, vm::ptr<sys_page_attr_t> attr)
ppu_error_code sys_memory_get_page_attribute(u32 addr, vm::ptr<sys_page_attr_t> attr)
{
sys_memory.error("sys_memory_get_page_attribute(addr=0x%x, attr=*0x%x)", addr, attr);
LV2_LOCK;
// TODO: Implement per thread page attribute setting.
attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE
attr->access_right = 0xFull; // SYS_MEMORY_ACCESS_RIGHT_ANY
@ -194,35 +157,29 @@ s32 sys_memory_get_page_attribute(u32 addr, vm::ptr<sys_page_attr_t> attr)
return CELL_OK;
}
s32 sys_memory_get_user_memory_size(vm::ptr<sys_memory_info_t> mem_info)
ppu_error_code sys_memory_get_user_memory_size(vm::ptr<sys_memory_info_t> mem_info)
{
sys_memory.warning("sys_memory_get_user_memory_size(mem_info=*0x%x)", mem_info);
LV2_LOCK;
// Get "default" memory container
const auto dct = fxm::get_always<lv2_memory_container>();
u32 reserved = 0;
mem_info->total_user_memory = dct->size;
mem_info->available_user_memory = dct->size - dct->used;
// Check all memory containers
idm::select<lv2_memory_container_t>([&](u32, lv2_memory_container_t& ct)
// Scan other memory containers
idm::select<lv2_memory_container>([&](u32, lv2_memory_container& ct)
{
reserved += ct.size;
mem_info->total_user_memory -= ct.size;
});
const auto area = vm::get(vm::user_space);
// Fetch the user memory available
mem_info->total_user_memory = area->size - reserved;
mem_info->available_user_memory = area->size - area->used;
return CELL_OK;
}
s32 sys_memory_container_create(vm::ptr<u32> cid, u32 size)
ppu_error_code sys_memory_container_create(vm::ptr<u32> cid, u32 size)
{
sys_memory.warning("sys_memory_container_create(cid=*0x%x, size=0x%x)", cid, size);
LV2_LOCK;
// Round down to 1 MB granularity
size &= ~0xfffff;
@ -231,66 +188,67 @@ s32 sys_memory_container_create(vm::ptr<u32> cid, u32 size)
return CELL_ENOMEM;
}
u32 reserved = 0;
const auto dct = fxm::get_always<lv2_memory_container>();
// Check all memory containers
idm::select<lv2_memory_container_t>([&](u32, lv2_memory_container_t& ct)
{
reserved += ct.size;
});
const auto area = vm::get(vm::user_space);
if (area->size < reserved + size || area->size - area->used < size)
// Try to obtain "physical memory" from the default container
if (!dct->take(size))
{
return CELL_ENOMEM;
}
// Create the memory container
*cid = idm::make<lv2_memory_container_t>(size);
*cid = idm::make<lv2_memory_container>(size);
return CELL_OK;
}
s32 sys_memory_container_destroy(u32 cid)
ppu_error_code sys_memory_container_destroy(u32 cid)
{
sys_memory.warning("sys_memory_container_destroy(cid=0x%x)", cid);
LV2_LOCK;
ppu_error_code result{};
const auto ct = idm::get<lv2_memory_container_t>(cid);
const auto ct = idm::withdraw<lv2_memory_container>(cid, [&](u32, lv2_memory_container& ct)
{
// Check if some memory is not deallocated (the container cannot be destroyed in this case)
if (!ct.used.compare_and_swap_test(0, ct.size))
{
result = CELL_EBUSY;
return_ false;
}
if (!ct)
return_ true;
});
if (!ct && !result)
{
return CELL_ESRCH;
}
// Check if some memory is not deallocated (the container cannot be destroyed in this case)
if (ct->used)
if (!ct)
{
return CELL_EBUSY;
return result;
}
idm::remove<lv2_memory_container_t>(cid);
// Return "physical memory" to the default container
fxm::get<lv2_memory_container>()->used -= ct->size;
return CELL_OK;
}
s32 sys_memory_container_get_size(vm::ptr<sys_memory_info_t> mem_info, u32 cid)
ppu_error_code sys_memory_container_get_size(vm::ptr<sys_memory_info_t> mem_info, u32 cid)
{
sys_memory.warning("sys_memory_container_get_size(mem_info=*0x%x, cid=0x%x)", mem_info, cid);
LV2_LOCK;
const auto ct = idm::get<lv2_memory_container_t>(cid);
const auto ct = idm::get<lv2_memory_container>(cid);
if (!ct)
{
return CELL_ESRCH;
}
mem_info->total_user_memory = ct->size; // total container memory
mem_info->available_user_memory = ct->size - ct->used; // available container memory
mem_info->total_user_memory = ct->size; // Total container memory
mem_info->available_user_memory = ct->size - ct->used; // Available container memory
return CELL_OK;
}

View File

@ -1,6 +1,8 @@
#pragma once
#include "sys_sync.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/IdManager.h"
enum : u32
{
@ -42,33 +44,45 @@ struct sys_page_attr_t
be_t<u32> pad;
};
#include <map>
struct lv2_memory_container_t
struct lv2_memory_container
{
// Amount of "physical" memory in this container
const u32 size;
const u32 size = 0x10000000; // Amount of "physical" memory in this container
const id_value<> id{};
// Amount of memory allocated
atomic_t<u32> used{ 0 };
atomic_t<u32> used{}; // Amount of "physical" memory currently used
// Allocations (addr -> size)
std::map<u32, u32> allocs;
lv2_memory_container() = default;
lv2_memory_container_t(u32 size)
lv2_memory_container(u32 size)
: size(size)
{
}
// Try to get specified amount of "physical" memory
u32 take(u32 amount)
{
const u32 old_value = used.fetch_op([&](u32& value)
{
if (size - value >= amount)
{
value += amount;
}
});
if (size - old_value >= amount)
{
return amount;
}
return 0;
}
};
// SysCalls
s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr);
s32 sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr);
s32 sys_memory_free(u32 start_addr);
s32 sys_memory_get_page_attribute(u32 addr, vm::ptr<sys_page_attr_t> attr);
s32 sys_memory_get_user_memory_size(vm::ptr<sys_memory_info_t> mem_info);
s32 sys_memory_container_create(vm::ptr<u32> cid, u32 size);
s32 sys_memory_container_destroy(u32 cid);
s32 sys_memory_container_get_size(vm::ptr<sys_memory_info_t> mem_info, u32 cid);
ppu_error_code sys_memory_allocate(u32 size, u64 flags, vm::ps3::ptr<u32> alloc_addr);
ppu_error_code sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ps3::ptr<u32> alloc_addr);
ppu_error_code sys_memory_free(u32 start_addr);
ppu_error_code sys_memory_get_page_attribute(u32 addr, vm::ps3::ptr<sys_page_attr_t> attr);
ppu_error_code sys_memory_get_user_memory_size(vm::ps3::ptr<sys_memory_info_t> mem_info);
ppu_error_code sys_memory_container_create(vm::ps3::ptr<u32> cid, u32 size);
ppu_error_code sys_memory_container_destroy(u32 cid);
ppu_error_code sys_memory_container_get_size(vm::ps3::ptr<sys_memory_info_t> mem_info, u32 cid);

View File

@ -1,19 +1,14 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_mmapper.h"
namespace vm { using namespace ps3; }
logs::channel sys_mmapper("sys_mmapper", logs::level::notice);
s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr)
ppu_error_code sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr)
{
sys_mmapper.error("sys_mmapper_allocate_address(size=0x%llx, flags=0x%llx, alignment=0x%llx, alloc_addr=*0x%x)", size, flags, alignment, alloc_addr);
LV2_LOCK;
if (size % 0x10000000)
{
return CELL_EALIGN;
@ -24,9 +19,8 @@ s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32
return CELL_ENOMEM;
}
// This is a 'hack' / workaround for psl1ght, which gives us an alignment of 0, which is technically invalid,
// but apparently is allowed on actual ps3
// https://github.com/ps3dev/PSL1GHT/blob/534e58950732c54dc6a553910b653c99ba6e9edc/ppu/librt/sbrk.c#L71
// This is a workaround for psl1ght, which gives us an alignment of 0, which is technically invalid, but apparently is allowed on actual ps3
// https://github.com/ps3dev/PSL1GHT/blob/534e58950732c54dc6a553910b653c99ba6e9edc/ppu/librt/sbrk.c#L71
if (!alignment)
{
alignment = 0x10000000;
@ -43,8 +37,7 @@ s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32
{
if (const auto area = vm::map(static_cast<u32>(addr), static_cast<u32>(size), flags))
{
*alloc_addr = addr;
*alloc_addr = static_cast<u32>(addr);
return CELL_OK;
}
}
@ -56,12 +49,10 @@ s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32
return CELL_EALIGN;
}
s32 sys_mmapper_allocate_fixed_address()
ppu_error_code sys_mmapper_allocate_fixed_address()
{
sys_mmapper.error("sys_mmapper_allocate_fixed_address()");
LV2_LOCK;
if (!vm::map(0xB0000000, 0x10000000)) // TODO: set correct flags (they aren't used currently though)
{
return CELL_EEXIST;
@ -70,12 +61,9 @@ s32 sys_mmapper_allocate_fixed_address()
return CELL_OK;
}
// Allocate physical memory (create lv2_memory_t object)
s32 sys_mmapper_allocate_memory(u64 size, u64 flags, vm::ptr<u32> mem_id)
ppu_error_code sys_mmapper_allocate_shared_memory(u64 unk, u32 size, u64 flags, vm::ptr<u32> mem_id)
{
sys_mmapper.warning("sys_mmapper_allocate_memory(size=0x%llx, flags=0x%llx, mem_id=*0x%x)", size, flags, mem_id);
LV2_LOCK;
sys_mmapper.warning("sys_mmapper_allocate_shared_memory(0x%llx, size=0x%x, flags=0x%llx, mem_id=*0x%x)", unk, size, flags, mem_id);
// Check page granularity
switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
@ -106,35 +94,23 @@ s32 sys_mmapper_allocate_memory(u64 size, u64 flags, vm::ptr<u32> mem_id)
}
}
if (size > UINT32_MAX)
// Get "default" memory container
const auto dct = fxm::get_always<lv2_memory_container>();
if (!dct->take(size))
{
return CELL_ENOMEM;
}
const u32 align =
flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 :
flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 :
throw EXCEPTION("Unexpected");
// Generate a new mem ID
*mem_id = idm::make<lv2_memory_t>(static_cast<u32>(size), align, flags, nullptr);
*mem_id = idm::make<lv2_memory>(size, flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000, flags, dct);
return CELL_OK;
}
s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id)
ppu_error_code sys_mmapper_allocate_shared_memory_from_container(u64 unk, u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id)
{
sys_mmapper.error("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", size, cid, flags, mem_id);
LV2_LOCK;
// Check if this container ID is valid.
const auto ct = idm::get<lv2_memory_container_t>(cid);
if (!ct)
{
return CELL_ESRCH;
}
sys_mmapper.error("sys_mmapper_allocate_shared_memory_from_container(0x%llx, size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", unk, size, cid, flags, mem_id);
// Check page granularity.
switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
@ -165,93 +141,100 @@ s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm:
}
}
if (ct->size - ct->used < size)
ppu_error_code result{};
const auto ct = idm::get<lv2_memory_container>(cid, [&](u32, lv2_memory_container& ct)
{
return CELL_ENOMEM;
// Try to get "physical memory"
if (!ct.take(size))
{
result = CELL_ENOMEM;
return_ false;
}
return_ true;
});
if (!ct && !result)
{
return CELL_ESRCH;
}
const u32 align =
flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 :
flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 :
throw EXCEPTION("Unexpected");
ct->used += size;
if (!ct)
{
return result;
}
// Generate a new mem ID
*mem_id = idm::make<lv2_memory_t>(size, align, flags, ct);
*mem_id = idm::make<lv2_memory>(size, flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000, flags, ct);
return CELL_OK;
}
s32 sys_mmapper_change_address_access_right(u32 addr, u64 flags)
ppu_error_code sys_mmapper_change_address_access_right(u32 addr, u64 flags)
{
sys_mmapper.todo("sys_mmapper_change_address_access_right(addr=0x%x, flags=0x%llx)", addr, flags);
return CELL_OK;
}
s32 sys_mmapper_free_address(u32 addr)
ppu_error_code sys_mmapper_free_address(u32 addr)
{
sys_mmapper.error("sys_mmapper_free_address(addr=0x%x)", addr);
LV2_LOCK;
// Try to unmap area
const auto area = vm::unmap(addr, true);
const auto area = vm::get(vm::any, addr);
if (!area || addr != area->addr)
if (!area)
{
return CELL_EINVAL;
}
if (area->used)
if (!area.unique())
{
return CELL_EBUSY;
}
if (!vm::unmap(addr))
{
throw EXCEPTION("Unexpected (failed to unmap memory ad 0x%x)", addr);
}
return CELL_OK;
}
s32 sys_mmapper_free_memory(u32 mem_id)
ppu_error_code sys_mmapper_free_shared_memory(u32 mem_id)
{
sys_mmapper.warning("sys_mmapper_free_memory(mem_id=0x%x)", mem_id);
sys_mmapper.warning("sys_mmapper_free_shared_memory(mem_id=0x%x)", mem_id);
LV2_LOCK;
ppu_error_code result{};
// Check if this mem ID is valid.
const auto mem = idm::get<lv2_memory_t>(mem_id);
// Conditionally remove memory ID
const auto mem = idm::withdraw<lv2_memory>(mem_id, [&](u32, lv2_memory& mem)
{
if (mem.addr.compare_and_swap_test(0, -1))
{
result = CELL_EBUSY;
return_ false;
}
if (!mem)
return_ true;
});
if (!mem && !result)
{
return CELL_ESRCH;
}
if (mem->addr)
if (!mem)
{
return CELL_EBUSY;
return result;
}
// Return physical memory to the container if necessary
if (mem->ct)
{
mem->ct->used -= mem->size;
}
// Release the allocated memory and remove the ID
idm::remove<lv2_memory_t>(mem_id);
// Return "physical memory" to the memory container
mem->ct->used -= mem->size;
return CELL_OK;
}
s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags)
ppu_error_code sys_mmapper_map_shared_memory(u32 addr, u32 mem_id, u64 flags)
{
sys_mmapper.error("sys_mmapper_map_memory(addr=0x%x, mem_id=0x%x, flags=0x%llx)", addr, mem_id, flags);
LV2_LOCK;
sys_mmapper.error("sys_mmapper_map_shared_memory(addr=0x%x, mem_id=0x%x, flags=0x%llx)", addr, mem_id, flags);
const auto area = vm::get(vm::any, addr);
@ -260,7 +243,7 @@ s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags)
return CELL_EINVAL;
}
const auto mem = idm::get<lv2_memory_t>(mem_id);
const auto mem = idm::get<lv2_memory>(mem_id);
if (!mem)
{
@ -272,28 +255,26 @@ s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags)
return CELL_EALIGN;
}
if (const u32 old_addr = mem->addr)
if (const u32 old_addr = mem->addr.compare_and_swap(0, -1))
{
sys_mmapper.warning("sys_mmapper_map_memory: Already mapped (mem_id=0x%x, addr=0x%x)", mem_id, old_addr);
sys_mmapper.warning("sys_mmapper_map_shared_memory(): Already mapped (mem_id=0x%x, addr=0x%x)", mem_id, old_addr);
return CELL_OK;
}
if (!area->falloc(addr, mem->size))
{
mem->addr = 0;
return CELL_EBUSY;
}
mem->addr = addr;
return CELL_OK;
}
s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr<u32> alloc_addr)
ppu_error_code sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr<u32> alloc_addr)
{
sys_mmapper.error("sys_mmapper_search_and_map(start_addr=0x%x, mem_id=0x%x, flags=0x%llx, alloc_addr=*0x%x)", start_addr, mem_id, flags, alloc_addr);
LV2_LOCK;
const auto area = vm::get(vm::any, start_addr);
if (!area || start_addr != area->addr || start_addr < 0x30000000 || start_addr >= 0xC0000000)
@ -301,30 +282,34 @@ s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr<u3
return CELL_EINVAL;
}
const auto mem = idm::get<lv2_memory_t>(mem_id);
const auto mem = idm::get<lv2_memory>(mem_id);
if (!mem)
{
return CELL_ESRCH;
}
if (const u32 old_addr = mem->addr.compare_and_swap(0, -1))
{
sys_mmapper.warning("sys_mmapper_search_and_map(): Already mapped (mem_id=0x%x, addr=0x%x)", mem_id, old_addr);
return CELL_OK;
}
const u32 addr = area->alloc(mem->size, mem->align);
if (!addr)
{
mem->addr = 0;
return CELL_ENOMEM;
}
*alloc_addr = addr;
*alloc_addr = mem->addr = addr;
return CELL_OK;
}
s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_id)
ppu_error_code sys_mmapper_unmap_shared_memory(u32 addr, vm::ptr<u32> mem_id)
{
sys_mmapper.error("sys_mmapper_unmap_memory(addr=0x%x, mem_id=*0x%x)", addr, mem_id);
LV2_LOCK;
sys_mmapper.error("sys_mmapper_unmap_shared_memory(addr=0x%x, mem_id=*0x%x)", addr, mem_id);
const auto area = vm::get(vm::any, addr);
@ -333,9 +318,15 @@ s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_id)
return CELL_EINVAL;
}
const auto mem = idm::select<lv2_memory_t>([&](u32, lv2_memory_t& mem)
const auto mem = idm::select<lv2_memory>([&](u32 id, lv2_memory& mem)
{
return mem.addr == addr;
if (mem.addr == addr)
{
*mem_id = id;
return true;
}
return false;
});
if (!mem)
@ -343,19 +334,13 @@ s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_id)
return CELL_EINVAL;
}
if (!area->dealloc(addr))
{
throw EXCEPTION("Deallocation failed (mem_id=0x%x, addr=0x%x)", mem->id, addr);
}
mem->addr = 0;
*mem_id = mem->id;
VERIFY(area->dealloc(addr));
VERIFY(mem->addr.exchange(0) == addr);
return CELL_OK;
}
s32 sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq)
ppu_error_code sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq)
{
sys_mmapper.todo("sys_mmapper_enable_page_fault_notification(addr=0x%x, eq=0x%x)", addr, eq);

View File

@ -2,18 +2,16 @@
#include "sys_memory.h"
struct lv2_memory_t
struct lv2_memory
{
const u32 size; // memory size
const u32 align; // required alignment
const u32 size; // Memory size
const u32 align; // Alignment required
const u64 flags;
const std::shared_ptr<lv2_memory_container_t> ct; // memory container the physical memory is taken from
const std::shared_ptr<lv2_memory_container> ct; // Associated memory container
const id_value<> id{};
atomic_t<u32> addr{}; // Actual mapping address
atomic_t<u32> addr{ 0 }; // actual mapping address
lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr<lv2_memory_container_t> ct)
lv2_memory(u32 size, u32 align, u64 flags, const std::shared_ptr<lv2_memory_container>& ct)
: size(size)
, align(align)
, flags(flags)
@ -23,14 +21,14 @@ struct lv2_memory_t
};
// SysCalls
s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr);
s32 sys_mmapper_allocate_fixed_address();
s32 sys_mmapper_allocate_memory(u64 size, u64 flags, vm::ptr<u32> mem_id);
s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id);
s32 sys_mmapper_change_address_access_right(u32 addr, u64 flags);
s32 sys_mmapper_free_address(u32 addr);
s32 sys_mmapper_free_memory(u32 mem_id);
s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags);
s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr<u32> alloc_addr);
s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_id);
s32 sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq);
ppu_error_code sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ps3::ptr<u32> alloc_addr);
ppu_error_code sys_mmapper_allocate_fixed_address();
ppu_error_code sys_mmapper_allocate_shared_memory(u64 unk, u32 size, u64 flags, vm::ps3::ptr<u32> mem_id);
ppu_error_code sys_mmapper_allocate_shared_memory_from_container(u64 unk, u32 size, u32 cid, u64 flags, vm::ps3::ptr<u32> mem_id);
ppu_error_code sys_mmapper_change_address_access_right(u32 addr, u64 flags);
ppu_error_code sys_mmapper_free_address(u32 addr);
ppu_error_code sys_mmapper_free_shared_memory(u32 mem_id);
ppu_error_code sys_mmapper_map_shared_memory(u32 addr, u32 mem_id, u64 flags);
ppu_error_code sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ps3::ptr<u32> alloc_addr);
ppu_error_code sys_mmapper_unmap_shared_memory(u32 addr, vm::ps3::ptr<u32> mem_id);
ppu_error_code sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq);

View File

@ -74,7 +74,7 @@ s32 sys_process_get_number_of_object(u32 object, vm::ptr<u32> nump)
switch(object)
{
case SYS_MEM_OBJECT: *nump = idm::get_count<lv2_memory_t>(); break;
case SYS_MEM_OBJECT: *nump = idm::get_count<lv2_memory>(); break;
case SYS_MUTEX_OBJECT: *nump = idm::get_count<lv2_mutex_t>(); break;
case SYS_COND_OBJECT: *nump = idm::get_count<lv2_cond_t>(); break;
case SYS_RWLOCK_OBJECT: *nump = idm::get_count<lv2_rwlock_t>(); break;
@ -89,7 +89,7 @@ s32 sys_process_get_number_of_object(u32 object, vm::ptr<u32> nump)
case SYS_LWMUTEX_OBJECT: *nump = idm::get_count<lv2_lwmutex_t>(); break;
case SYS_TIMER_OBJECT: *nump = idm::get_count<lv2_timer_t>(); break;
case SYS_SEMAPHORE_OBJECT: *nump = idm::get_count<lv2_sema_t>(); break;
case SYS_FS_FD_OBJECT: *nump = idm::get_count<lv2_fs_object_t>(); break;
case SYS_FS_FD_OBJECT: *nump = idm::get_count<lv2_fs_object>(); break;
case SYS_LWCOND_OBJECT: *nump = idm::get_count<lv2_lwcond_t>(); break;
case SYS_EVENT_FLAG_OBJECT: *nump = idm::get_count<lv2_event_flag_t>(); break;
@ -121,7 +121,7 @@ s32 sys_process_get_id(u32 object, vm::ptr<u32> buffer, u32 size, vm::ptr<u32> s
switch (object)
{
case SYS_MEM_OBJECT: idm_get_set<lv2_memory_t>(objects); break;
case SYS_MEM_OBJECT: idm_get_set<lv2_memory>(objects); break;
case SYS_MUTEX_OBJECT: idm_get_set<lv2_mutex_t>(objects); break;
case SYS_COND_OBJECT: idm_get_set<lv2_cond_t>(objects); break;
case SYS_RWLOCK_OBJECT: idm_get_set<lv2_rwlock_t>(objects); break;
@ -136,7 +136,7 @@ s32 sys_process_get_id(u32 object, vm::ptr<u32> buffer, u32 size, vm::ptr<u32> s
case SYS_LWMUTEX_OBJECT: idm_get_set<lv2_lwmutex_t>(objects); break;
case SYS_TIMER_OBJECT: idm_get_set<lv2_timer_t>(objects); break;
case SYS_SEMAPHORE_OBJECT: idm_get_set<lv2_sema_t>(objects); break;
case SYS_FS_FD_OBJECT: idm_get_set<lv2_fs_object_t>(objects); break;
case SYS_FS_FD_OBJECT: idm_get_set<lv2_fs_object>(objects); break;
case SYS_LWCOND_OBJECT: idm_get_set<lv2_lwcond_t>(objects); break;
case SYS_EVENT_FLAG_OBJECT: idm_get_set<lv2_event_flag_t>(objects); break;

View File

@ -1,25 +1,21 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_tty.h"
namespace vm { using namespace ps3; }
logs::channel sys_tty("sys_tty", logs::level::notice);
extern fs::file g_tty;
s32 sys_tty_read(s32 ch, vm::ptr<char> buf, u32 len, vm::ptr<u32> preadlen)
ppu_error_code sys_tty_read(s32 ch, vm::ptr<char> buf, u32 len, vm::ptr<u32> preadlen)
{
sys_tty.todo("sys_tty_read(ch=%d, buf=*0x%x, len=%d, preadlen=*0x%x)", ch, buf, len, preadlen);
sys_tty.fatal("sys_tty_read(ch=%d, buf=*0x%x, len=%d, preadlen=*0x%x)", ch, buf, len, preadlen);
// We currently do not support reading from the Console
*preadlen = 0;
Emu.Pause();
return CELL_OK;
throw std::runtime_error("Unimplemented" HERE);
}
s32 sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen)
ppu_error_code sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen)
{
sys_tty.notice("sys_tty_write(ch=%d, buf=*0x%x, len=%d, pwritelen=*0x%x)", ch, buf, len, pwritelen);
@ -28,7 +24,7 @@ s32 sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen)
return CELL_EINVAL;
}
if ((s32)len <= 0)
if (static_cast<s32>(len) <= 0)
{
*pwritelen = 0;

View File

@ -1,6 +1,7 @@
#pragma once
namespace vm { using namespace ps3; }
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/ErrorCodes.h"
// TTY channels
enum
@ -25,5 +26,5 @@ enum
};
// SysCalls
s32 sys_tty_read(s32 ch, vm::ptr<char> buf, u32 len, vm::ptr<u32> preadlen);
s32 sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen);
ppu_error_code sys_tty_read(s32 ch, vm::ps3::ptr<char> buf, u32 len, vm::ps3::ptr<u32> preadlen);
ppu_error_code sys_tty_write(s32 ch, vm::ps3::cptr<char> buf, u32 len, vm::ps3::ptr<u32> pwritelen);

View File

@ -1,43 +1,46 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_memory.h"
#include "sys_vm.h"
#include "sys_memory.h"
namespace vm { using namespace ps3; }
logs::channel sys_vm("sys_vm", logs::level::notice);
s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
ppu_error_code sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
{
sys_vm.error("sys_vm_memory_map(vsize=0x%x, psize=0x%x, cid=0x%x, flags=0x%llx, policy=0x%llx, addr=*0x%x)", vsize, psize, cid, flag, policy, addr);
LV2_LOCK;
// Use fixed address (TODO: search and use some free address instead)
const u32 new_addr = vm::check_addr(0x60000000) ? 0x70000000 : 0x60000000;
// Map memory
const auto area = vm::map(new_addr, vsize, flag);
// Alloc memory
if (!area || !area->alloc(vsize))
if (!vsize || !psize || vsize & 0x2000000 || vsize > 0x10000000 || psize > 0x10000000 || policy != SYS_VM_POLICY_AUTO_RECOMMENDED)
{
return CELL_ENOMEM;
return CELL_EINVAL;
}
// Write a pointer for the allocated memory.
*addr = new_addr;
if (cid != SYS_MEMORY_CONTAINER_ID_INVALID && !idm::check<lv2_memory_container>(cid))
{
return CELL_ESRCH;
}
return CELL_OK;
// Look for unmapped space (roughly)
for (u32 found = 0x60000000; found <= 0xC0000000 - vsize; found += 0x2000000)
{
// Try to map
if (const auto area = vm::map(found, vsize, flag))
{
// Alloc all memory (shall not fail)
VERIFY(area->alloc(vsize));
// Write a pointer for the allocated memory
*addr = found;
return CELL_OK;
}
}
return CELL_ENOMEM;
}
s32 sys_vm_unmap(u32 addr)
ppu_error_code sys_vm_unmap(u32 addr)
{
sys_vm.error("sys_vm_unmap(addr=0x%x)", addr);
LV2_LOCK;
sys_vm.warning("sys_vm_unmap(addr=0x%x)", addr);
if (!vm::unmap(addr))
{
@ -47,81 +50,81 @@ s32 sys_vm_unmap(u32 addr)
return CELL_OK;
}
s32 sys_vm_append_memory(u32 addr, u32 size)
ppu_error_code sys_vm_append_memory(u32 addr, u32 size)
{
sys_vm.todo("sys_vm_append_memory(addr=0x%x, size=0x%x)", addr, size);
sys_vm.warning("sys_vm_append_memory(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_return_memory(u32 addr, u32 size)
ppu_error_code sys_vm_return_memory(u32 addr, u32 size)
{
sys_vm.todo("sys_vm_return_memory(addr=0x%x, size=0x%x)", addr, size);
sys_vm.warning("sys_vm_return_memory(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_lock(u32 addr, u32 size)
ppu_error_code sys_vm_lock(u32 addr, u32 size)
{
sys_vm.todo("sys_vm_lock(addr=0x%x, size=0x%x)", addr, size);
sys_vm.warning("sys_vm_lock(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_unlock(u32 addr, u32 size)
ppu_error_code sys_vm_unlock(u32 addr, u32 size)
{
sys_vm.todo("sys_vm_unlock(addr=0x%x, size=0x%x)", addr, size);
sys_vm.warning("sys_vm_unlock(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_touch(u32 addr, u32 size)
ppu_error_code sys_vm_touch(u32 addr, u32 size)
{
sys_vm.todo("sys_vm_touch(addr=0x%x, size=0x%x)", addr, size);
sys_vm.warning("sys_vm_touch(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_flush(u32 addr, u32 size)
ppu_error_code sys_vm_flush(u32 addr, u32 size)
{
sys_vm.todo("sys_vm_flush(addr=0x%x, size=0x%x)", addr, size);
sys_vm.warning("sys_vm_flush(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_invalidate(u32 addr, u32 size)
ppu_error_code sys_vm_invalidate(u32 addr, u32 size)
{
sys_vm.todo("sys_vm_invalidate(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_store(u32 addr, u32 size)
ppu_error_code sys_vm_store(u32 addr, u32 size)
{
sys_vm.todo("sys_vm_store(addr=0x%x, size=0x%x)", addr, size);
sys_vm.warning("sys_vm_store(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_sync(u32 addr, u32 size)
ppu_error_code sys_vm_sync(u32 addr, u32 size)
{
sys_vm.todo("sys_vm_sync(addr=0x%x, size=0x%x)", addr, size);
sys_vm.warning("sys_vm_sync(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_test(u32 addr, u32 size, vm::ptr<u64> result)
ppu_error_code sys_vm_test(u32 addr, u32 size, vm::ptr<u64> result)
{
sys_vm.todo("sys_vm_test(addr=0x%x, size=0x%x, result=*0x%x)", addr, size, result);
sys_vm.warning("sys_vm_test(addr=0x%x, size=0x%x, result=*0x%x)", addr, size, result);
*result = SYS_VM_STATE_ON_MEMORY;
return CELL_OK;
}
s32 sys_vm_get_statistics(u32 addr, vm::ptr<sys_vm_statistics_t> stat)
ppu_error_code sys_vm_get_statistics(u32 addr, vm::ptr<sys_vm_statistics_t> stat)
{
sys_vm.todo("sys_vm_get_statistics(addr=0x%x, stat=*0x%x)", addr, stat);
sys_vm.warning("sys_vm_get_statistics(addr=0x%x, stat=*0x%x)", addr, stat);
stat->page_fault_ppu = 0;
stat->page_fault_spu = 0;

View File

@ -1,6 +1,8 @@
#pragma once
#include "sys_sync.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/IdManager.h"
enum : u64
{
@ -8,6 +10,8 @@ enum : u64
SYS_VM_STATE_UNUSED = 1ull,
SYS_VM_STATE_ON_MEMORY = 2ull,
SYS_VM_STATE_STORED = 4ull,
SYS_VM_POLICY_AUTO_RECOMMENDED = 1ull,
};
struct sys_vm_statistics_t
@ -22,16 +26,16 @@ struct sys_vm_statistics_t
};
// SysCalls
s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
s32 sys_vm_unmap(u32 addr);
s32 sys_vm_append_memory(u32 addr, u32 size);
s32 sys_vm_return_memory(u32 addr, u32 size);
s32 sys_vm_lock(u32 addr, u32 size);
s32 sys_vm_unlock(u32 addr, u32 size);
s32 sys_vm_touch(u32 addr, u32 size);
s32 sys_vm_flush(u32 addr, u32 size);
s32 sys_vm_invalidate(u32 addr, u32 size);
s32 sys_vm_store(u32 addr, u32 size);
s32 sys_vm_sync(u32 addr, u32 size);
s32 sys_vm_test(u32 addr, u32 size, vm::ptr<u64> result);
s32 sys_vm_get_statistics(u32 addr, vm::ptr<sys_vm_statistics_t> stat);
ppu_error_code sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ps3::ptr<u32> addr);
ppu_error_code sys_vm_unmap(u32 addr);
ppu_error_code sys_vm_append_memory(u32 addr, u32 size);
ppu_error_code sys_vm_return_memory(u32 addr, u32 size);
ppu_error_code sys_vm_lock(u32 addr, u32 size);
ppu_error_code sys_vm_unlock(u32 addr, u32 size);
ppu_error_code sys_vm_touch(u32 addr, u32 size);
ppu_error_code sys_vm_flush(u32 addr, u32 size);
ppu_error_code sys_vm_invalidate(u32 addr, u32 size);
ppu_error_code sys_vm_store(u32 addr, u32 size);
ppu_error_code sys_vm_sync(u32 addr, u32 size);
ppu_error_code sys_vm_test(u32 addr, u32 size, vm::ps3::ptr<u64> result);
ppu_error_code sys_vm_get_statistics(u32 addr, vm::ps3::ptr<sys_vm_statistics_t> stat);

View File

@ -24,6 +24,8 @@
#include "wait_engine.h"
#include <mutex>
namespace vm
{
thread_local u64 g_tls_fault_count{};
@ -482,7 +484,7 @@ namespace vm
return true;
}
u32 alloc(u32 size, memory_location_t location, u32 align)
u32 alloc(u32 size, memory_location_t location, u32 align, u32 sup)
{
const auto block = get(location);
@ -491,10 +493,10 @@ namespace vm
throw EXCEPTION("Invalid memory location (%d)", location);
}
return block->alloc(size, align);
return block->alloc(size, align, sup);
}
u32 falloc(u32 addr, u32 size, memory_location_t location)
u32 falloc(u32 addr, u32 size, memory_location_t location, u32 sup)
{
const auto block = get(location, addr);
@ -503,10 +505,10 @@ namespace vm
throw EXCEPTION("Invalid memory location (%d, addr=0x%x)", location, addr);
}
return block->falloc(addr, size);
return block->falloc(addr, size, sup);
}
bool dealloc(u32 addr, memory_location_t location)
u32 dealloc(u32 addr, memory_location_t location, u32* sup_out)
{
const auto block = get(location, addr);
@ -515,7 +517,7 @@ namespace vm
throw EXCEPTION("Invalid memory location (%d, addr=0x%x)", location, addr);
}
return block->dealloc(addr);
return block->dealloc(addr, sup_out);
}
void dealloc_verbose_nothrow(u32 addr, memory_location_t location) noexcept
@ -535,9 +537,9 @@ namespace vm
}
}
bool block_t::try_alloc(u32 addr, u32 size)
bool block_t::try_alloc(u32 addr, u32 size, u32 sup)
{
// check if memory area is already mapped
// Check if memory area is already mapped
for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++)
{
if (g_pages[i])
@ -546,86 +548,70 @@ namespace vm
}
}
// try to reserve "physical" memory
if (!used.atomic_op([=](u32& used) -> bool
{
if (used > this->size)
{
throw EXCEPTION("Unexpected memory amount used (0x%x)", used);
}
if (used + size > this->size)
{
return false;
}
used += size;
return true;
}))
{
return false;
}
// map memory pages
// Map "real" memory pages
_page_map(addr, size, page_readable | page_writable);
// add entry
// Add entry
m_map[addr] = size;
// Add supplementary info if necessary
if (sup) m_sup[addr] = sup;
return true;
}
block_t::block_t(u32 addr, u32 size, u64 flags)
: addr(addr)
, size(size)
, flags(flags)
{
}
block_t::~block_t()
{
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
// deallocate all memory
// Deallocate all memory
for (auto& entry : m_map)
{
_page_unmap(entry.first, entry.second);
}
}
u32 block_t::alloc(u32 size, u32 align)
u32 block_t::alloc(u32 size, u32 align, u32 sup)
{
std::lock_guard<std::mutex> lock(m_mutex);
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
// align to minimal page size
// Align to minimal page size
size = ::align(size, 4096);
// check alignment (it's page allocation, so passing small values there is just silly)
// Check alignment (it's page allocation, so passing small values there is just silly)
if (align < 4096 || align != (0x80000000u >> cntlz32(align)))
{
throw EXCEPTION("Invalid alignment (size=0x%x, align=0x%x)", size, align);
}
// return if size is invalid
// Return if size is invalid
if (!size || size > this->size)
{
return 0;
}
// search for an appropriate place (unoptimized)
// Search for an appropriate place (unoptimized)
for (u32 addr = ::align(this->addr, align); addr < this->addr + this->size - 1; addr += align)
{
if (try_alloc(addr, size))
if (try_alloc(addr, size, sup))
{
return addr;
}
if (used + size > this->size)
{
return 0;
}
}
return 0;
}
u32 block_t::falloc(u32 addr, u32 size)
u32 block_t::falloc(u32 addr, u32 size, u32 sup)
{
std::lock_guard<std::mutex> lock(m_mutex);
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
// align to minimal page size
size = ::align(size, 4096);
@ -636,7 +622,7 @@ namespace vm
return 0;
}
if (!try_alloc(addr, size))
if (!try_alloc(addr, size, sup))
{
return 0;
}
@ -644,9 +630,9 @@ namespace vm
return addr;
}
bool block_t::dealloc(u32 addr)
u32 block_t::dealloc(u32 addr, u32* sup_out)
{
std::lock_guard<std::mutex> lock(m_mutex);
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
const auto found = m_map.find(addr);
@ -654,19 +640,36 @@ namespace vm
{
const u32 size = found->second;
// remove entry
// Remove entry
m_map.erase(found);
// return "physical" memory
used -= size;
// Unmap "real" memory pages
_page_unmap(addr, size);
// unmap memory pages
std::lock_guard<reservation_mutex_t>{ g_reservation_mutex }, _page_unmap(addr, size);
// Write supplementary info if necessary
if (sup_out) *sup_out = m_sup[addr];
return true;
// Remove supplementary info
m_sup.erase(addr);
return size;
}
return false;
return 0;
}
u32 block_t::used()
{
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
u32 result = 0;
for (auto& entry : m_map)
{
result += entry.second;
}
return result;
}
std::shared_ptr<block_t> map(u32 addr, u32 size, u64 flags)
@ -706,7 +709,7 @@ namespace vm
return block;
}
std::shared_ptr<block_t> unmap(u32 addr)
std::shared_ptr<block_t> unmap(u32 addr, bool must_be_empty)
{
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
@ -714,6 +717,11 @@ namespace vm
{
if (*it && (*it)->addr == addr)
{
if (must_be_empty && (!it->unique() || (*it)->used()))
{
return *it;
}
auto block = std::move(*it);
g_locations.erase(it);
return block;

View File

@ -1,7 +1,6 @@
#pragma once
#include <map>
#include <mutex>
class thread_ctrl;
@ -80,13 +79,13 @@ namespace vm
bool check_addr(u32 addr, u32 size = 1);
// Search and map memory in specified memory location (don't pass alignment smaller than 4096)
u32 alloc(u32 size, memory_location_t location, u32 align = 4096);
u32 alloc(u32 size, memory_location_t location, u32 align = 4096, u32 sup = 0);
// Map memory at specified address (in optionally specified memory location)
u32 falloc(u32 addr, u32 size, memory_location_t location = any);
u32 falloc(u32 addr, u32 size, memory_location_t location = any, u32 sup = 0);
// Unmap memory at specified address (in optionally specified memory location)
bool dealloc(u32 addr, memory_location_t location = any);
// Unmap memory at specified address (in optionally specified memory location), return size
u32 dealloc(u32 addr, memory_location_t location = any, u32* sup_out = nullptr);
// dealloc() with no return value and no exceptions
void dealloc_verbose_nothrow(u32 addr, memory_location_t location = any) noexcept;
@ -94,46 +93,41 @@ namespace vm
// Object that handles memory allocations inside specific constant bounds ("location")
class block_t final
{
std::map<u32, u32> m_map; // addr -> size mapping of mapped locations
std::mutex m_mutex;
std::map<u32, u32> m_map; // Mapped memory: addr -> size
std::unordered_map<u32, u32> m_sup; // Supplementary info for allocations
bool try_alloc(u32 addr, u32 size);
bool try_alloc(u32 addr, u32 size, u32 sup);
public:
block_t(u32 addr, u32 size, u64 flags = 0)
: addr(addr)
, size(size)
, flags(flags)
, used(0)
{
}
block_t(u32 addr, u32 size, u64 flags = 0);
~block_t();
public:
const u32 addr; // start address
const u32 size; // total size
const u64 flags; // currently unused
atomic_t<u32> used; // amount of memory used, may be increased manually to prevent some memory from allocating
const u32 addr; // Start address
const u32 size; // Total size
const u64 flags; // Currently unused
// Search and map memory (don't pass alignment smaller than 4096)
u32 alloc(u32 size, u32 align = 4096);
u32 alloc(u32 size, u32 align = 4096, u32 sup = 0);
// Try to map memory at fixed location
u32 falloc(u32 addr, u32 size);
u32 falloc(u32 addr, u32 size, u32 sup = 0);
// Unmap memory at specified location previously returned by alloc()
bool dealloc(u32 addr);
// Unmap memory at specified location previously returned by alloc(), return size
u32 dealloc(u32 addr, u32* sup_out = nullptr);
// Get allocated memory count
u32 used();
};
// create new memory block with specified parameters and return it
// Create new memory block with specified parameters and return it
std::shared_ptr<block_t> map(u32 addr, u32 size, u64 flags = 0);
// delete existing memory block with specified start address
std::shared_ptr<block_t> unmap(u32 addr);
// Delete existing memory block with specified start address, return it
std::shared_ptr<block_t> unmap(u32 addr, bool must_be_empty = false);
// get memory block associated with optionally specified memory location or optionally specified address
// Get memory block associated with optionally specified memory location or optionally specified address
std::shared_ptr<block_t> get(memory_location_t location, u32 addr = 0);
// Get PS3/PSV virtual memory address from the provided pointer (nullptr always converted to 0)

View File

@ -130,6 +130,18 @@ namespace vm
return aligned(ALIGN_32(T));
}
// Get type size
static constexpr u32 size()
{
return SIZE_32(T);
}
// Get type alignment
static constexpr u32 align()
{
return ALIGN_32(T);
}
// Test address for arbitrary alignment: (addr & (align - 1)) != 0
explicit_bool_t operator %(u32 align) const
{
@ -266,9 +278,11 @@ namespace vm
// Native endianness pointer to LE data
template<typename T, typename AT = u32> using ptrl = _ptr_base<to_le_t<T>, AT>;
template<typename T, typename AT = u32> using cptrl = ptrl<const T, AT>;
// Native endianness pointer to BE data
template<typename T, typename AT = u32> using ptrb = _ptr_base<to_be_t<T>, AT>;
template<typename T, typename AT = u32> using cptrb = ptrb<const T, AT>;
// BE pointer to LE data
template<typename T, typename AT = u32> using bptrl = _ptr_base<to_le_t<T>, to_be_t<AT>>;
@ -286,24 +300,19 @@ namespace vm
{
// Default pointer type for PS3 HLE functions (Native endianness pointer to BE data)
template<typename T, typename AT = u32> using ptr = ptrb<T, AT>;
template<typename T, typename AT = u32> using cptr = ptr<const T, AT>;
// Default pointer to pointer type for PS3 HLE functions (Native endianness pointer to BE pointer to BE data)
template<typename T, typename AT = u32, typename AT2 = u32> using pptr = ptr<ptr<T, AT2>, AT>;
template<typename T, typename AT = u32, typename AT2 = u32> using cpptr = pptr<const T, AT, AT2>;
// Default pointer type for PS3 HLE structures (BE pointer to BE data)
template<typename T, typename AT = u32> using bptr = bptrb<T, AT>;
template<typename T, typename AT = u32> using bcptr = bptr<const T, AT>;
// Default pointer to pointer type for PS3 HLE structures (BE pointer to BE pointer to BE data)
template<typename T, typename AT = u32, typename AT2 = u32> using bpptr = bptr<ptr<T, AT2>, AT>;
// Native endianness pointer to const BE data
template<typename T, typename AT = u32> using cptr = ptr<const T, AT>;
// BE pointer to const BE data
template<typename T, typename AT = u32> using bcptr = bptr<const T, AT>;
template<typename T, typename AT = u32> using cpptr = pptr<const T, AT>;
template<typename T, typename AT = u32> using bcpptr = bpptr<const T, AT>;
template<typename T, typename AT = u32, typename AT2 = u32> using bcpptr = bpptr<const T, AT, AT2>;
// Perform static_cast (for example, vm::ptr<void> to vm::ptr<char>)
template<typename CT, typename T, typename AT, typename = decltype(static_cast<to_be_t<CT>*>(std::declval<T*>()))>
@ -324,23 +333,18 @@ namespace vm
{
// Default pointer type for PSV HLE functions (Native endianness pointer to LE data)
template<typename T> using ptr = ptrl<T>;
template<typename T> using cptr = ptr<const T>;
// Default pointer to pointer type for PSV HLE functions (Native endianness pointer to LE pointer to LE data)
template<typename T> using pptr = ptr<ptr<T>>;
template<typename T> using cpptr = pptr<const T>;
// Default pointer type for PSV HLE structures (LE pointer to LE data)
template<typename T> using lptr = lptrl<T>;
template<typename T> using lcptr = lptr<const T>;
// Default pointer to pointer type for PSV HLE structures (LE pointer to LE pointer to LE data)
template<typename T> using lpptr = lptr<ptr<T>>;
// Native endianness pointer to const LE data
template<typename T> using cptr = ptr<const T>;
// LE pointer to const LE data
template<typename T> using lcptr = lptr<const T>;
template<typename T> using cpptr = pptr<const T>;
template<typename T> using lcpptr = lpptr<const T>;
// Perform static_cast (for example, vm::ptr<void> to vm::ptr<char>)

View File

@ -109,10 +109,10 @@ namespace vm
template<typename T, typename A = stack_allocator> using var = varb<T, A>;
// Make BE variable initialized from value
template<typename T> inline auto make_var(const T& value)
template<typename T>
inline auto make_var(const T& value)
{
varb<T, stack_allocator> var(value);
return var;
return varb<T>(value);
}
// Global HLE variable
@ -128,10 +128,10 @@ namespace vm
template<typename T, typename A = stack_allocator> using var = varl<T, A>;
// Make LE variable initialized from value
template<typename T> inline auto make_var(const T& value)
template<typename T>
inline auto make_var(const T& value)
{
varl<T, stack_allocator> var(value);
return var;
return varl<T>(value);
}
// Global HLE variable

View File

@ -28,10 +28,17 @@
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot", true);
cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes");
std::string g_cfg_defaults;
cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir()
cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/");
cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/");
cfg::string_entry g_cfg_vfs_dev_flash(cfg::root.vfs, "/dev_flash/", "$(EmulatorDir)dev_flash/");
cfg::string_entry g_cfg_vfs_dev_usb000(cfg::root.vfs, "/dev_usb000/", "$(EmulatorDir)dev_usb000/");
cfg::string_entry g_cfg_vfs_dev_bdvd(cfg::root.vfs, "/dev_bdvd/"); // Not mounted
cfg::string_entry g_cfg_vfs_app_home(cfg::root.vfs, "/app_home/"); // Not mounted
extern cfg::string_entry g_cfg_vfs_dev_bdvd;
extern cfg::string_entry g_cfg_vfs_app_home;
cfg::bool_entry g_cfg_vfs_allow_host_root(cfg::root.vfs, "Enable /host_root/", true);
std::string g_cfg_defaults;
extern atomic_t<u32> g_thread_count;
@ -124,6 +131,22 @@ bool Emulator::BootGame(const std::string& path, bool direct)
return false;
}
std::string Emulator::GetGameDir()
{
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
return fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir) + "game/";
}
std::string Emulator::GetLibDir()
{
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
return fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir) + "sys/external/";
}
void Emulator::Load()
{
Stop();
@ -208,33 +231,49 @@ void Emulator::Load()
LOG_NOTICE(LOADER, "Title: %s", GetTitle());
LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());
LOG_NOTICE(LOADER, "");
LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string());
// Mount all devices
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
const std::string& bdvd_dir = g_cfg_vfs_dev_bdvd;
const std::string& home_dir = g_cfg_vfs_app_home;
// Mount /dev_bdvd/
if (g_cfg_vfs_dev_bdvd.size() == 0 && fs::is_file(elf_dir + "/../../PS3_DISC.SFB"))
vfs::mount("dev_hdd0", fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_hdd1", fmt::replace_all(g_cfg_vfs_dev_hdd1, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_flash", fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_usb", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_usb000", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));
// Mount /dev_bdvd/ if necessary
if (bdvd_dir.empty() && fs::is_file(elf_dir + "/../../PS3_DISC.SFB"))
{
const auto dir_list = fmt::split(elf_dir, { "/", "\\" });
// Check latest two directories
if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME")
{
g_cfg_vfs_dev_bdvd = elf_dir.substr(0, elf_dir.length() - 15);
vfs::mount("dev_bdvd", elf_dir.substr(0, elf_dir.length() - 15));
}
else
{
g_cfg_vfs_dev_bdvd = elf_dir + "/../../";
vfs::mount("dev_bdvd", elf_dir + "/../../");
}
}
// Mount /app_home/
if (g_cfg_vfs_app_home.size() == 0)
LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));
}
else if (bdvd_dir.size())
{
g_cfg_vfs_app_home = elf_dir + '/';
vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir));
}
vfs::dump();
// Mount /host_root/ if necessary
if (g_cfg_vfs_allow_host_root)
{
vfs::mount("host_root", {});
}
LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string());
ppu_load_exec(ppu_exec);

View File

@ -172,6 +172,9 @@ public:
bool BootGame(const std::string& path, bool direct = false);
static std::string GetGameDir();
static std::string GetLibDir();
void Load();
void Run();
bool Pause();

View File

@ -1,79 +1,51 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "IdManager.h"
#include "VFS.h"
#include "Utilities/StrUtil.h"
#include <regex>
cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir()
cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/");
cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/");
cfg::string_entry g_cfg_vfs_dev_flash(cfg::root.vfs, "/dev_flash/", "$(EmulatorDir)dev_flash/");
cfg::string_entry g_cfg_vfs_dev_usb000(cfg::root.vfs, "/dev_usb000/", "$(EmulatorDir)dev_usb000/");
cfg::string_entry g_cfg_vfs_dev_bdvd(cfg::root.vfs, "/dev_bdvd/"); // Not mounted
cfg::string_entry g_cfg_vfs_app_home(cfg::root.vfs, "/app_home/"); // Not mounted
cfg::bool_entry g_cfg_vfs_allow_host_root(cfg::root.vfs, "Enable /host_root/", true);
void vfs::dump()
struct vfs_manager
{
LOG_NOTICE(LOADER, "Mount info:");
LOG_NOTICE(LOADER, "/dev_hdd0/ -> %s", g_cfg_vfs_dev_hdd0.get());
LOG_NOTICE(LOADER, "/dev_hdd1/ -> %s", g_cfg_vfs_dev_hdd1.get());
LOG_NOTICE(LOADER, "/dev_flash/ -> %s", g_cfg_vfs_dev_flash.get());
LOG_NOTICE(LOADER, "/dev_usb/ -> %s", g_cfg_vfs_dev_usb000.get());
LOG_NOTICE(LOADER, "/dev_usb000/ -> %s", g_cfg_vfs_dev_usb000.get());
if (g_cfg_vfs_dev_bdvd.size()) LOG_NOTICE(LOADER, "/dev_bdvd/ -> %s", g_cfg_vfs_dev_bdvd.get());
if (g_cfg_vfs_app_home.size()) LOG_NOTICE(LOADER, "/app_home/ -> %s", g_cfg_vfs_app_home.get());
if (g_cfg_vfs_allow_host_root) LOG_NOTICE(LOADER, "/host_root/ -> .");
LOG_NOTICE(LOADER, "");
shared_mutex mutex;
// Device name -> Real path
std::unordered_map<std::string, std::string> mounted;
};
const std::regex s_regex_ps3("^/+(.*?)(?:$|/)(.*)", std::regex::optimize);
const std::regex s_regex_psv("^(.*?):(.*)", std::regex::optimize);
bool vfs::mount(const std::string& dev_name, const std::string& path)
{
const auto table = fxm::get_always<vfs_manager>();
writer_lock lock(table->mutex);
return table->mounted.emplace(dev_name, path).second;
}
std::string vfs::get(const std::string& vpath)
std::string vfs::get(const std::string& vpath, vfs::type _type)
{
const cfg::string_entry* vdir = nullptr;
std::size_t f_pos = vpath.find_first_not_of('/');
std::size_t start = 0;
std::smatch match;
// Compare vpath with device name
auto detect = [&](const auto& vdev) -> bool
if (!std::regex_match(vpath, match, _type == type::ps3 ? s_regex_ps3 : s_regex_psv))
{
const std::size_t size = ::size32(vdev) - 1; // Char array size
if (f_pos && f_pos != -1 && vpath.compare(f_pos - 1, size, vdev, size) == 0)
{
start = size;
return true;
}
return false;
};
if (g_cfg_vfs_allow_host_root && detect("/host_root/"))
return vpath.substr(start); // Accessing host FS directly
else if (detect("/dev_hdd0/"))
vdir = &g_cfg_vfs_dev_hdd0;
else if (detect("/dev_hdd1/"))
vdir = &g_cfg_vfs_dev_hdd1;
else if (detect("/dev_flash/"))
vdir = &g_cfg_vfs_dev_flash;
else if (detect("/dev_usb000/"))
vdir = &g_cfg_vfs_dev_usb000;
else if (detect("/dev_usb/"))
vdir = &g_cfg_vfs_dev_usb000;
else if (detect("/dev_bdvd/"))
vdir = &g_cfg_vfs_dev_bdvd;
else if (detect("/app_home/"))
vdir = &g_cfg_vfs_app_home;
// Return empty path if not mounted
if (!vdir || !start)
{
LOG_WARNING(GENERAL, "vfs::get() failed for %s", vpath);
LOG_WARNING(GENERAL, "vfs::get(): invalid input: %s", vpath);
return{};
}
// Replace $(EmulatorDir), concatenate
return fmt::replace_all(*vdir, "$(EmulatorDir)", g_cfg_vfs_emulator_dir.size() == 0 ? fs::get_executable_dir() : g_cfg_vfs_emulator_dir) + vpath.substr(start);
const auto table = fxm::get_always<vfs_manager>();
reader_lock lock(table->mutex);
const auto found = table->mounted.find(match.str(1));
if (found == table->mounted.end())
{
LOG_WARNING(GENERAL, "vfs::get(): device not found: %s", vpath);
return{};
}
// Concatenate
return found->second + match.str(2);
}

View File

@ -2,9 +2,16 @@
namespace vfs
{
// Print mounted directories
void dump();
// VFS type
enum class type
{
ps3,
psv,
};
// Convert PS3/PSV path to fs-compatible path
std::string get(const std::string& vpath);
// Mount VFS device
bool mount(const std::string& dev_name, const std::string& path);
// Convert VFS path to fs path
std::string get(const std::string& vpath, type _type = type::ps3);
}

View File

@ -42,7 +42,6 @@ GameViewer::GameViewer(wxWindow* parent) : wxListView(parent)
m_sortColumn = 1;
m_sortAscending = true;
m_path = "/dev_hdd0/game/";
m_popup = new wxMenu();
Bind(wxEVT_LIST_ITEM_ACTIVATED, &GameViewer::DClick, this);
@ -80,7 +79,7 @@ void GameViewer::LoadGames()
{
m_games.clear();
for (const auto& entry : fs::dir(vfs::get(m_path)))
for (const auto& entry : fs::dir(Emu.GetGameDir()))
{
if (entry.is_directory)
{
@ -93,10 +92,13 @@ void GameViewer::LoadPSF()
{
m_game_data.clear();
const std::string& game_path = Emu.GetGameDir();
for (u32 i = 0; i < m_games.size(); ++i)
{
const std::string sfb = vfs::get(m_path) + m_games[i] + "/PS3_DISC.SFB";
const std::string sfo = vfs::get(m_path) + m_games[i] + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO");
const std::string& dir = game_path + m_games[i];
const std::string& sfb = dir + "/PS3_DISC.SFB";
const std::string& sfo = dir + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO");
const fs::file sfo_file(sfo);
if (!sfo_file)
@ -125,27 +127,27 @@ void GameViewer::LoadPSF()
if (game.category == "HG")
{
game.category = "HDD Game";
game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG";
game.icon_path = dir + "/ICON0.PNG";
}
else if (game.category == "DG")
{
game.category = "Disc Game";
game.icon_path = vfs::get(m_path) + m_games[i] + "/PS3_GAME/ICON0.PNG";
game.icon_path = dir + "/PS3_GAME/ICON0.PNG";
}
else if (game.category == "HM")
{
game.category = "Home";
game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG";
game.icon_path = dir + "/ICON0.PNG";
}
else if (game.category == "AV")
{
game.category = "Audio/Video";
game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG";
game.icon_path = dir + "/ICON0.PNG";
}
else if (game.category == "GD")
{
game.category = "Game Data";
game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG";
game.icon_path = dir + "/ICON0.PNG";
}
m_game_data.push_back(game);
@ -183,13 +185,13 @@ void GameViewer::DClick(wxListEvent& event)
long i = GetFirstSelected();
if (i < 0) return;
const std::string& path = m_path + m_game_data[i].root;
const std::string& path = Emu.GetGameDir() + m_game_data[i].root;
Emu.Stop();
if (!Emu.BootGame(vfs::get(path)))
if (!Emu.BootGame(path))
{
LOG_ERROR(LOADER, "Failed to boot %s", path);
LOG_ERROR(LOADER, "Failed to boot /dev_hdd0/game/%s", m_game_data[i].root);
}
}
@ -238,7 +240,7 @@ void GameViewer::RemoveGame(wxCommandEvent& event)
if (wxMessageBox("Permanently delete game files?", "Confirm Delete", wxYES_NO | wxNO_DEFAULT) == wxYES)
{
fs::remove_all(vfs::get(m_path) + this->GetItemText(i, 6).ToStdString());
fs::remove_all(Emu.GetGameDir() + this->GetItemText(i, 6).ToStdString());
}
Refresh();

View File

@ -63,7 +63,6 @@ class GameViewer : public wxListView
{
int m_sortColumn;
bool m_sortAscending;
std::string m_path;
std::vector<std::string> m_games;
std::vector<GameInfo> m_game_data;
ColumnsArr m_columns;

View File

@ -57,7 +57,7 @@ KernelExplorer::KernelExplorer(wxWindow* parent)
void KernelExplorer::Update()
{
m_tree->DeleteAllItems();
const u32 total_memory_usage = vm::get(vm::user_space)->used.load();
const u32 total_memory_usage = vm::get(vm::user_space)->used();
const auto& root = m_tree->AddRoot(fmt::format("Process, ID = 0x00000001, Total Memory Usage = 0x%x (%0.2f MB)", total_memory_usage, (float)total_memory_usage / (1024 * 1024)));
@ -198,22 +198,22 @@ void KernelExplorer::Update()
}
// Memory Containers
if (const u32 count = idm::get_count<lv2_memory_container_t>())
if (const u32 count = idm::get_count<lv2_memory_container>())
{
const auto& node = m_tree->AppendItem(root, fmt::format("Memory Containers (%zu)", count));
idm::select<lv2_memory_container_t>([&](u32 id, lv2_memory_container_t&)
idm::select<lv2_memory_container>([&](u32 id, lv2_memory_container&)
{
m_tree->AppendItem(node, fmt::format("Memory Container: ID = 0x%08x", id));
});
}
// Memory Objects
if (const u32 count = idm::get_count<lv2_memory_t>())
if (const u32 count = idm::get_count<lv2_memory>())
{
const auto& node = m_tree->AppendItem(root, fmt::format("Memory Objects (%zu)", count));
idm::select<lv2_memory_t>([&](u32 id, lv2_memory_t&)
idm::select<lv2_memory>([&](u32 id, lv2_memory&)
{
m_tree->AppendItem(node, fmt::format("Memory Object: ID = 0x%08x", id));
});

View File

@ -253,7 +253,7 @@ void MainFrame::InstallPkg(wxCommandEvent& WXUNUSED(event))
pkg_f.seek(0);
// Get full path
const auto& local_path = vfs::get("/dev_hdd0/game/") + std::string(std::begin(title_id), std::end(title_id));
const auto& local_path = Emu.GetGameDir() + std::string(std::begin(title_id), std::end(title_id));
if (!fs::create_dir(local_path))
{

View File

@ -332,7 +332,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent)
chbox_list_core_lle->Check(chbox_list_core_lle->Append(unk));
}
const std::string& lle_dir = vfs::get("/dev_flash/sys/external/"); // TODO
const std::string& lle_dir = Emu.GetLibDir(); // TODO
std::unordered_set<std::string> set(data.begin(), data.end());
std::vector<std::string> lle_module_list_unselected;

View File

@ -32,6 +32,12 @@ enum class elf_machine : u16
mips = 0x08,
};
template<typename T>
using elf_be = be_t<T>;
template<typename T>
using elf_le = le_t<T>;
template<template<typename T> class en_t, typename sz_t>
struct elf_ehdr
{
@ -341,7 +347,7 @@ public:
}
};
using ppu_exec_object = elf_object<be_t, u64, elf_machine::ppc64, elf_os::none, elf_type::exec>;
using ppu_prx_object = elf_object<be_t, u64, elf_machine::ppc64, elf_os::lv2, elf_type::prx>;
using spu_exec_object = elf_object<be_t, u32, elf_machine::spu, elf_os::none, elf_type::exec>;
using arm_exec_object = elf_object<le_t, u32, elf_machine::arm, elf_os::none, elf_type::none>;
using ppu_exec_object = elf_object<elf_be, u64, elf_machine::ppc64, elf_os::none, elf_type::exec>;
using ppu_prx_object = elf_object<elf_be, u64, elf_machine::ppc64, elf_os::lv2, elf_type::prx>;
using spu_exec_object = elf_object<elf_be, u32, elf_machine::spu, elf_os::none, elf_type::exec>;
using arm_exec_object = elf_object<elf_le, u32, elf_machine::arm, elf_os::none, elf_type::none>;