mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-10 21:40:43 +00:00
commit
260865de6d
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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>)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
});
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user