2014-07-31 18:08:02 +02:00
|
|
|
#pragma once
|
2015-07-11 22:44:53 +02:00
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
#include <map>
|
2016-07-28 22:55:16 +02:00
|
|
|
#include <functional>
|
|
|
|
|
#include <memory>
|
2015-01-07 17:44:47 +01:00
|
|
|
|
2016-04-25 12:49:12 +02:00
|
|
|
class thread_ctrl;
|
|
|
|
|
|
2014-07-31 18:08:02 +02:00
|
|
|
namespace vm
|
|
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
extern u8* const g_base_addr;
|
|
|
|
|
extern u8* const g_priv_addr;
|
2015-02-13 16:26:42 +01:00
|
|
|
|
2015-07-11 22:44:53 +02:00
|
|
|
enum memory_location_t : uint
|
2014-11-19 15:16:30 +01:00
|
|
|
{
|
|
|
|
|
main,
|
2015-02-13 15:04:03 +01:00
|
|
|
user_space,
|
2015-07-11 22:44:53 +02:00
|
|
|
video,
|
2014-11-19 15:16:30 +01:00
|
|
|
stack,
|
2015-07-11 22:44:53 +02:00
|
|
|
|
|
|
|
|
memory_location_max,
|
|
|
|
|
any = 0xffffffff,
|
2015-02-13 15:04:03 +01:00
|
|
|
};
|
2014-11-24 19:12:04 +01:00
|
|
|
|
2015-02-13 15:04:03 +01:00
|
|
|
enum page_info_t : u8
|
|
|
|
|
{
|
|
|
|
|
page_readable = (1 << 0),
|
|
|
|
|
page_writable = (1 << 1),
|
|
|
|
|
page_executable = (1 << 2),
|
2014-11-19 15:16:30 +01:00
|
|
|
|
2015-02-13 15:04:03 +01:00
|
|
|
page_fault_notification = (1 << 3),
|
|
|
|
|
page_no_reservations = (1 << 4),
|
|
|
|
|
|
|
|
|
|
page_allocated = (1 << 7),
|
2014-11-19 15:16:30 +01:00
|
|
|
};
|
|
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
// Address type
|
|
|
|
|
enum addr_t : u32 {};
|
|
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
struct access_violation : std::runtime_error
|
|
|
|
|
{
|
|
|
|
|
access_violation(u64 addr, const char* cause);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
[[noreturn]] void throw_access_violation(u64 addr, const char* cause);
|
|
|
|
|
|
2015-07-21 22:14:04 +02:00
|
|
|
// This flag is changed by various reservation functions and may have different meaning.
|
|
|
|
|
// reservation_break() - true if the reservation was successfully broken.
|
|
|
|
|
// reservation_acquire() - true if another existing reservation was broken.
|
|
|
|
|
// reservation_free() - true if this thread's reservation was successfully removed.
|
|
|
|
|
// reservation_op() - false if reservation_update() would succeed if called instead.
|
|
|
|
|
// Write access to reserved memory - only set to true if the reservation was broken.
|
|
|
|
|
extern thread_local bool g_tls_did_break_reservation;
|
|
|
|
|
|
2015-07-11 22:44:53 +02:00
|
|
|
// Unconditionally break the reservation at specified address
|
|
|
|
|
void reservation_break(u32 addr);
|
|
|
|
|
|
|
|
|
|
// Reserve memory at the specified address for further atomic update
|
|
|
|
|
void reservation_acquire(void* data, u32 addr, u32 size);
|
|
|
|
|
|
|
|
|
|
// Attempt to atomically update previously reserved memory
|
2015-02-07 00:39:51 +01:00
|
|
|
bool reservation_update(u32 addr, const void* data, u32 size);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
|
|
|
|
// Process a memory access error if it's caused by the reservation
|
2015-02-17 01:08:23 +01:00
|
|
|
bool reservation_query(u32 addr, u32 size, bool is_writing, std::function<bool()> callback);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
2015-07-12 13:52:55 +02:00
|
|
|
// Returns true if the current thread owns reservation
|
2016-05-13 16:01:48 +02:00
|
|
|
bool reservation_test(thread_ctrl* current);
|
2015-07-12 13:52:55 +02:00
|
|
|
|
2015-07-11 22:44:53 +02:00
|
|
|
// Break all reservations created by the current thread
|
2015-02-07 00:39:51 +01:00
|
|
|
void reservation_free();
|
2015-07-11 22:44:53 +02:00
|
|
|
|
|
|
|
|
// Perform atomic operation unconditionally
|
2015-02-07 14:46:42 +01:00
|
|
|
void reservation_op(u32 addr, u32 size, std::function<void()> proc);
|
2015-02-07 00:39:51 +01:00
|
|
|
|
2015-07-11 22:44:53 +02:00
|
|
|
// Change memory protection of specified memory region
|
2015-02-13 15:04:03 +01:00
|
|
|
bool page_protect(u32 addr, u32 size, u8 flags_test = 0, u8 flags_set = 0, u8 flags_clear = 0);
|
|
|
|
|
|
2015-07-11 22:44:53 +02:00
|
|
|
// Check if existing memory range is allocated. Checking address before using it is very unsafe.
|
|
|
|
|
// Return value may be wrong. Even if it's true and correct, actual memory protection may be read-only and no-access.
|
2015-02-13 15:04:03 +01:00
|
|
|
bool check_addr(u32 addr, u32 size = 1);
|
|
|
|
|
|
2015-07-11 22:44:53 +02:00
|
|
|
// Search and map memory in specified memory location (don't pass alignment smaller than 4096)
|
2016-05-25 20:04:08 +02:00
|
|
|
u32 alloc(u32 size, memory_location_t location, u32 align = 4096, u32 sup = 0);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
|
|
|
|
// Map memory at specified address (in optionally specified memory location)
|
2016-05-25 20:04:08 +02:00
|
|
|
u32 falloc(u32 addr, u32 size, memory_location_t location = any, u32 sup = 0);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
2016-05-25 20:04:08 +02:00
|
|
|
// 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);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
2015-08-19 13:04:58 +02:00
|
|
|
// dealloc() with no return value and no exceptions
|
|
|
|
|
void dealloc_verbose_nothrow(u32 addr, memory_location_t location = any) noexcept;
|
|
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
// Object that handles memory allocations inside specific constant bounds ("location")
|
2015-07-12 13:52:55 +02:00
|
|
|
class block_t final
|
2015-07-11 22:44:53 +02:00
|
|
|
{
|
2016-05-25 20:04:08 +02:00
|
|
|
std::map<u32, u32> m_map; // Mapped memory: addr -> size
|
|
|
|
|
std::unordered_map<u32, u32> m_sup; // Supplementary info for allocations
|
2015-07-11 22:44:53 +02:00
|
|
|
|
2016-05-25 20:04:08 +02:00
|
|
|
bool try_alloc(u32 addr, u32 size, u32 sup);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
|
|
|
|
public:
|
2016-05-25 20:04:08 +02:00
|
|
|
block_t(u32 addr, u32 size, u64 flags = 0);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
|
|
|
|
~block_t();
|
|
|
|
|
|
|
|
|
|
public:
|
2016-05-25 20:04:08 +02:00
|
|
|
const u32 addr; // Start address
|
|
|
|
|
const u32 size; // Total size
|
|
|
|
|
const u64 flags; // Currently unused
|
2015-07-11 22:44:53 +02:00
|
|
|
|
|
|
|
|
// Search and map memory (don't pass alignment smaller than 4096)
|
2016-05-25 20:04:08 +02:00
|
|
|
u32 alloc(u32 size, u32 align = 4096, u32 sup = 0);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
|
|
|
|
// Try to map memory at fixed location
|
2016-05-25 20:04:08 +02:00
|
|
|
u32 falloc(u32 addr, u32 size, u32 sup = 0);
|
|
|
|
|
|
|
|
|
|
// Unmap memory at specified location previously returned by alloc(), return size
|
|
|
|
|
u32 dealloc(u32 addr, u32* sup_out = nullptr);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
2016-05-25 20:04:08 +02:00
|
|
|
// Get allocated memory count
|
|
|
|
|
u32 used();
|
2015-07-11 22:44:53 +02:00
|
|
|
};
|
|
|
|
|
|
2016-05-25 20:04:08 +02:00
|
|
|
// Create new memory block with specified parameters and return it
|
2015-07-12 13:52:55 +02:00
|
|
|
std::shared_ptr<block_t> map(u32 addr, u32 size, u64 flags = 0);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
2016-05-25 20:04:08 +02:00
|
|
|
// Delete existing memory block with specified start address, return it
|
|
|
|
|
std::shared_ptr<block_t> unmap(u32 addr, bool must_be_empty = false);
|
2015-07-11 22:44:53 +02:00
|
|
|
|
2016-05-25 20:04:08 +02:00
|
|
|
// Get memory block associated with optionally specified memory location or optionally specified address
|
2015-07-11 22:44:53 +02:00
|
|
|
std::shared_ptr<block_t> get(memory_location_t location, u32 addr = 0);
|
2014-08-31 11:54:12 +02:00
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
// Get PS3/PSV virtual memory address from the provided pointer (nullptr always converted to 0)
|
2016-05-13 16:01:48 +02:00
|
|
|
inline vm::addr_t get_addr(const void* real_ptr)
|
2015-02-07 00:39:51 +01:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
if (!real_ptr)
|
|
|
|
|
{
|
2016-05-13 16:01:48 +02:00
|
|
|
return vm::addr_t{};
|
2015-09-26 22:46:04 +02:00
|
|
|
}
|
2015-02-07 00:39:51 +01:00
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
const std::ptrdiff_t diff = static_cast<const u8*>(real_ptr) - g_base_addr;
|
2015-07-02 03:54:36 +02:00
|
|
|
const u32 res = static_cast<u32>(diff);
|
|
|
|
|
|
|
|
|
|
if (res == diff)
|
|
|
|
|
{
|
2016-05-13 16:01:48 +02:00
|
|
|
return static_cast<vm::addr_t>(res);
|
2015-07-02 03:54:36 +02:00
|
|
|
}
|
2015-01-19 20:41:31 +01:00
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
throw fmt::exception("Not a virtual memory pointer (%p)", real_ptr);
|
2015-09-26 22:46:04 +02:00
|
|
|
}
|
2015-01-29 16:48:05 +01:00
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
// Convert pointer-to-member to a vm address compatible offset
|
|
|
|
|
template<typename MT, typename T> inline u32 get_offset(MT T::*const member_ptr)
|
|
|
|
|
{
|
2016-01-14 18:13:41 +01:00
|
|
|
return static_cast<u32>(reinterpret_cast<std::uintptr_t>(&reinterpret_cast<char const volatile&>(reinterpret_cast<T*>(0ull)->*member_ptr)));
|
2015-07-02 03:54:36 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
template<typename T>
|
|
|
|
|
struct cast_impl
|
2015-01-14 14:57:19 +01:00
|
|
|
{
|
2016-02-01 22:52:49 +01:00
|
|
|
static_assert(std::is_same<T, u32>::value, "vm::cast() error: unsupported type");
|
2015-01-14 14:57:19 +01:00
|
|
|
};
|
|
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
template<>
|
|
|
|
|
struct cast_impl<u32>
|
2015-01-14 14:57:19 +01:00
|
|
|
{
|
2016-05-13 16:01:48 +02:00
|
|
|
static vm::addr_t cast(u32 addr, const char* loc)
|
|
|
|
|
{
|
|
|
|
|
return static_cast<vm::addr_t>(addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static vm::addr_t cast(u32 addr)
|
2015-01-14 14:57:19 +01:00
|
|
|
{
|
2016-05-13 16:01:48 +02:00
|
|
|
return static_cast<vm::addr_t>(addr);
|
2015-01-14 14:57:19 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
template<>
|
|
|
|
|
struct cast_impl<u64>
|
2015-01-14 14:57:19 +01:00
|
|
|
{
|
2016-05-13 16:01:48 +02:00
|
|
|
static vm::addr_t cast(u64 addr, const char* loc)
|
|
|
|
|
{
|
2016-08-03 22:51:05 +02:00
|
|
|
return static_cast<vm::addr_t>(static_cast<u32>(addr));
|
2016-05-13 16:01:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static vm::addr_t cast(u64 addr)
|
2015-01-14 14:57:19 +01:00
|
|
|
{
|
2016-08-03 22:51:05 +02:00
|
|
|
return static_cast<vm::addr_t>(static_cast<u32>(addr));
|
2015-01-14 14:57:19 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
template<typename T, bool Se>
|
|
|
|
|
struct cast_impl<se_t<T, Se>>
|
2015-01-14 14:57:19 +01:00
|
|
|
{
|
2016-05-13 16:01:48 +02:00
|
|
|
static vm::addr_t cast(const se_t<T, Se>& addr, const char* loc)
|
2015-01-14 14:57:19 +01:00
|
|
|
{
|
2016-02-01 22:52:49 +01:00
|
|
|
return cast_impl<T>::cast(addr, loc);
|
2015-06-21 01:04:01 +02:00
|
|
|
}
|
2016-05-13 16:01:48 +02:00
|
|
|
|
|
|
|
|
static vm::addr_t cast(const se_t<T, Se>& addr)
|
|
|
|
|
{
|
|
|
|
|
return cast_impl<T>::cast(addr);
|
|
|
|
|
}
|
2015-06-21 01:04:01 +02:00
|
|
|
};
|
|
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
template<typename T>
|
2016-05-13 16:01:48 +02:00
|
|
|
vm::addr_t cast(const T& addr, const char* loc)
|
2015-01-14 14:57:19 +01:00
|
|
|
{
|
2016-02-01 22:52:49 +01:00
|
|
|
return cast_impl<T>::cast(addr, loc);
|
2015-01-14 14:57:19 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
template<typename T>
|
|
|
|
|
vm::addr_t cast(const T& addr)
|
|
|
|
|
{
|
|
|
|
|
return cast_impl<T>::cast(addr);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
// Convert specified PS3/PSV virtual memory address to a pointer for common access
|
|
|
|
|
inline void* base(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return g_base_addr + addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert specified PS3/PSV virtual memory address to a pointer for privileged access (always readable/writable if allocated)
|
|
|
|
|
inline void* base_priv(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return g_priv_addr + addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline const u8& read8(u32 addr)
|
2014-08-31 11:54:12 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
return g_base_addr[addr];
|
2015-06-19 17:49:38 +02:00
|
|
|
}
|
2014-11-19 15:16:30 +01:00
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
inline void write8(u32 addr, u8 value)
|
2015-06-19 17:49:38 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
g_base_addr[addr] = value;
|
2015-06-19 17:49:38 +02:00
|
|
|
}
|
2014-09-15 00:17:24 +02:00
|
|
|
|
2015-06-19 17:49:38 +02:00
|
|
|
namespace ps3
|
|
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
// Convert specified PS3 address to a pointer of specified (possibly converted to BE) type
|
|
|
|
|
template<typename T> inline to_be_t<T>* _ptr(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return static_cast<to_be_t<T>*>(base(addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename T> inline to_be_t<T>* _ptr_priv(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return static_cast<to_be_t<T>*>(base_priv(addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert specified PS3 address to a reference of specified (possibly converted to BE) type
|
|
|
|
|
template<typename T> inline to_be_t<T>& _ref(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return *_ptr<T>(addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename T> inline to_be_t<T>& _ref_priv(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return *_ptr_priv<T>(addr);
|
|
|
|
|
}
|
2014-09-15 00:17:24 +02:00
|
|
|
|
2015-06-21 01:04:01 +02:00
|
|
|
inline const be_t<u16>& read16(u32 addr)
|
2014-08-31 11:54:12 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
return _ref<u16>(addr);
|
2014-09-15 00:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-21 01:04:01 +02:00
|
|
|
inline void write16(u32 addr, be_t<u16> value)
|
2014-08-31 11:54:12 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
_ref<u16>(addr) = value;
|
2014-09-15 00:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-21 01:04:01 +02:00
|
|
|
inline const be_t<u32>& read32(u32 addr)
|
|
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
return _ref<u32>(addr);
|
2014-08-31 11:54:12 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-21 01:04:01 +02:00
|
|
|
inline void write32(u32 addr, be_t<u32> value)
|
2014-08-31 11:54:12 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
_ref<u32>(addr) = value;
|
2014-08-31 11:54:12 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-21 01:04:01 +02:00
|
|
|
inline const be_t<u64>& read64(u32 addr)
|
2014-11-19 15:16:30 +01:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
return _ref<u64>(addr);
|
2014-11-19 15:16:30 +01:00
|
|
|
}
|
|
|
|
|
|
2015-06-21 01:04:01 +02:00
|
|
|
inline void write64(u32 addr, be_t<u64> value)
|
2014-11-19 15:16:30 +01:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
_ref<u64>(addr) = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace psv
|
|
|
|
|
{
|
|
|
|
|
template<typename T> inline to_le_t<T>* _ptr(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return static_cast<to_le_t<T>*>(base(addr));
|
2014-11-19 15:16:30 +01:00
|
|
|
}
|
|
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
template<typename T> inline to_le_t<T>* _ptr_priv(u32 addr)
|
2014-08-31 11:54:12 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
return static_cast<to_le_t<T>*>(base_priv(addr));
|
2014-09-15 00:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
template<typename T> inline to_le_t<T>& _ref(u32 addr)
|
2014-08-31 11:54:12 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
return *_ptr<T>(addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename T> inline to_le_t<T>& _ref_priv(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return *_ptr_priv<T>(addr);
|
2014-09-15 00:17:24 +02:00
|
|
|
}
|
2014-11-19 15:16:30 +01:00
|
|
|
|
2015-06-21 01:04:01 +02:00
|
|
|
inline const le_t<u16>& read16(u32 addr)
|
|
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
return _ref<u16>(addr);
|
2015-06-21 01:04:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void write16(u32 addr, le_t<u16> value)
|
|
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
_ref<u16>(addr) = value;
|
2015-06-21 01:04:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline const le_t<u32>& read32(u32 addr)
|
|
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
return _ref<u32>(addr);
|
2015-06-21 01:04:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void write32(u32 addr, le_t<u32> value)
|
2014-08-31 11:54:12 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
_ref<u32>(addr) = value;
|
2014-08-31 11:54:12 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-21 01:04:01 +02:00
|
|
|
inline const le_t<u64>& read64(u32 addr)
|
2014-08-31 11:54:12 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
return _ref<u64>(addr);
|
2014-08-31 11:54:12 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-21 01:04:01 +02:00
|
|
|
inline void write64(u32 addr, le_t<u64> value)
|
2014-08-31 11:54:12 +02:00
|
|
|
{
|
2015-09-26 22:46:04 +02:00
|
|
|
_ref<u64>(addr) = value;
|
2014-08-31 11:54:12 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
void init();
|
2014-08-31 11:54:12 +02:00
|
|
|
}
|
2014-11-19 15:16:30 +01:00
|
|
|
|
|
|
|
|
namespace psp
|
|
|
|
|
{
|
|
|
|
|
using namespace psv;
|
|
|
|
|
|
|
|
|
|
void init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void close();
|
2014-07-31 18:08:02 +02:00
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
u32 stack_push(u32 size, u32 align_v);
|
|
|
|
|
void stack_pop_verbose(u32 addr, u32 size) noexcept;
|
2014-11-24 19:12:04 +01:00
|
|
|
|
2016-02-01 22:52:49 +01:00
|
|
|
extern thread_local u64 g_tls_fault_count;
|
2014-11-24 19:12:04 +01:00
|
|
|
}
|
2015-07-28 23:34:22 +02:00
|
|
|
|
|
|
|
|
#include "vm_var.h"
|