mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 10:42:36 +01:00
Fix vm::range_lock, imporve vm::check_addr
This commit is contained in:
parent
6e27ab60ca
commit
fefab50e06
@ -390,13 +390,13 @@ extern bool ppu_patch(u32 addr, u32 value)
|
||||
|
||||
vm::reader_lock rlock;
|
||||
|
||||
if (!vm::check_addr(addr, sizeof(value)))
|
||||
if (!vm::check_addr(addr))
|
||||
{
|
||||
ppu_log.fatal("Patch failed at 0x%x: invalid memory address.", addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool is_exec = vm::check_addr(addr, sizeof(value), vm::page_executable);
|
||||
const bool is_exec = vm::check_addr(addr, vm::page_executable);
|
||||
|
||||
if (is_exec && g_cfg.core.ppu_decoder == ppu_decoder_type::llvm && !Emu.IsReady())
|
||||
{
|
||||
@ -444,18 +444,18 @@ std::string ppu_thread::dump_regs() const
|
||||
|
||||
fmt::append(ret, "r%d%s: 0x%-8llx", i, i <= 9 ? " " : "", reg);
|
||||
|
||||
const u32 max_str_len = 32;
|
||||
const u32 hex_count = 8;
|
||||
constexpr u32 max_str_len = 32;
|
||||
constexpr u32 hex_count = 8;
|
||||
|
||||
if (reg <= UINT32_MAX && vm::check_addr(static_cast<u32>(reg), max_str_len))
|
||||
if (reg <= UINT32_MAX && vm::check_addr<max_str_len>(static_cast<u32>(reg)))
|
||||
{
|
||||
bool is_function = false;
|
||||
u32 toc = 0;
|
||||
|
||||
if (const u32 reg_ptr = *vm::get_super_ptr<u32>(static_cast<u32>(reg));
|
||||
vm::check_addr(reg_ptr, max_str_len))
|
||||
vm::check_addr<max_str_len>(reg_ptr))
|
||||
{
|
||||
if ((reg | reg_ptr) % 4 == 0 && vm::check_addr(reg_ptr, 4, vm::page_executable))
|
||||
if ((reg | reg_ptr) % 4 == 0 && vm::check_addr(reg_ptr, vm::page_executable))
|
||||
{
|
||||
toc = *vm::get_super_ptr<u32>(static_cast<u32>(reg + 4));
|
||||
|
||||
@ -466,7 +466,7 @@ std::string ppu_thread::dump_regs() const
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (reg % 4 == 0 && vm::check_addr(reg, 4, vm::page_executable))
|
||||
else if (reg % 4 == 0 && vm::check_addr(reg, vm::page_executable))
|
||||
{
|
||||
is_function = true;
|
||||
}
|
||||
@ -577,7 +577,7 @@ std::vector<std::pair<u32, u32>> ppu_thread::dump_callstack_list() const
|
||||
|
||||
const u32 stack_ptr = static_cast<u32>(r1);
|
||||
|
||||
if (!vm::check_addr(stack_ptr, 1, vm::page_writable))
|
||||
if (!vm::check_addr(stack_ptr, vm::page_writable))
|
||||
{
|
||||
// Normally impossible unless the code does not follow ABI rules
|
||||
return {};
|
||||
@ -586,12 +586,12 @@ std::vector<std::pair<u32, u32>> ppu_thread::dump_callstack_list() const
|
||||
u32 stack_min = stack_ptr & ~0xfff;
|
||||
u32 stack_max = stack_min + 4096;
|
||||
|
||||
while (stack_min && vm::check_addr(stack_min - 4096, 4096, vm::page_writable))
|
||||
while (stack_min && vm::check_addr(stack_min - 4096, vm::page_writable))
|
||||
{
|
||||
stack_min -= 4096;
|
||||
}
|
||||
|
||||
while (stack_max + 4096 && vm::check_addr(stack_max, 4096, vm::page_writable))
|
||||
while (stack_max + 4096 && vm::check_addr(stack_max, vm::page_writable))
|
||||
{
|
||||
stack_max += 4096;
|
||||
}
|
||||
@ -610,7 +610,7 @@ std::vector<std::pair<u32, u32>> ppu_thread::dump_callstack_list() const
|
||||
|
||||
auto is_invalid = [](u64 addr)
|
||||
{
|
||||
if (addr > UINT32_MAX || addr % 4 || !vm::check_addr(static_cast<u32>(addr), 1, vm::page_executable))
|
||||
if (addr > UINT32_MAX || addr % 4 || !vm::check_addr(static_cast<u32>(addr), vm::page_executable))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -1140,7 +1140,7 @@ void ppu_trap(ppu_thread& ppu, u64 addr)
|
||||
u32 add = static_cast<u32>(g_cfg.core.stub_ppu_traps) * 4;
|
||||
|
||||
// If stubbing is enabled, check current instruction and the following
|
||||
if (!add || !vm::check_addr(ppu.cia, 4, vm::page_executable) || !vm::check_addr(ppu.cia + add, 4, vm::page_executable))
|
||||
if (!add || !vm::check_addr(ppu.cia, vm::page_executable) || !vm::check_addr(ppu.cia + add, vm::page_executable))
|
||||
{
|
||||
fmt::throw_exception("PPU Trap!" HERE);
|
||||
}
|
||||
@ -1686,7 +1686,7 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
if (raddr / 128 != addr / 128 || !ppu.use_full_rdata)
|
||||
{
|
||||
// Even when the reservation address does not match the target address must be valid
|
||||
if (!vm::check_addr(addr, 1, vm::page_writable))
|
||||
if (!vm::check_addr(addr, vm::page_writable))
|
||||
{
|
||||
// Access violate
|
||||
data += 0;
|
||||
|
@ -2699,7 +2699,7 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args)
|
||||
}
|
||||
}
|
||||
|
||||
if (!vm::check_addr(addr, 1, vm::page_writable))
|
||||
if (!vm::check_addr(addr, vm::page_writable))
|
||||
{
|
||||
vm::_ref<atomic_t<u8>>(addr) += 0; // Access violate
|
||||
}
|
||||
@ -3296,7 +3296,7 @@ bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data)
|
||||
if ((lock_val >> vm::range_pos) == (vm::range_locked >> vm::range_pos))
|
||||
{
|
||||
// All page flags are untouched and can be read safely
|
||||
if (!vm::check_addr(addr, 128))
|
||||
if (!vm::check_addr(addr))
|
||||
{
|
||||
// Assume our memory is being (de)allocated
|
||||
range_lock->release(0);
|
||||
@ -3327,7 +3327,7 @@ bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data)
|
||||
if (lock_addr + lock_size <= addr || lock_addr >= addr + 128)
|
||||
{
|
||||
// We are outside locked range, so page flags are unaffected
|
||||
if (!vm::check_addr(addr, 128))
|
||||
if (!vm::check_addr(addr))
|
||||
{
|
||||
range_lock->release(0);
|
||||
break;
|
||||
|
@ -16,18 +16,13 @@ error_code sys_dbg_read_process_memory(s32 pid, u32 address, u32 size, vm::ptr<v
|
||||
return CELL_LV2DBG_ERROR_DEINVALIDARGUMENTS;
|
||||
}
|
||||
|
||||
if (!vm::check_addr(address, size))
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
if (!size || !data)
|
||||
{
|
||||
return CELL_LV2DBG_ERROR_DEINVALIDARGUMENTS;
|
||||
}
|
||||
|
||||
// Check if data destination is writable
|
||||
if (!vm::check_addr(data.addr(), size, vm::page_writable))
|
||||
if (!vm::check_addr(data.addr(), vm::page_writable, size))
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
@ -47,18 +42,13 @@ error_code sys_dbg_write_process_memory(s32 pid, u32 address, u32 size, vm::cptr
|
||||
return CELL_LV2DBG_ERROR_DEINVALIDARGUMENTS;
|
||||
}
|
||||
|
||||
if (!vm::check_addr(address, size))
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
if (!size || !data)
|
||||
{
|
||||
return CELL_LV2DBG_ERROR_DEINVALIDARGUMENTS;
|
||||
}
|
||||
|
||||
// Check if data source is readable
|
||||
if (!vm::check_addr(data.addr(), size, vm::page_readable))
|
||||
if (!vm::check_addr(data.addr(), vm::page_readable, size))
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr<sys_
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (!vm::check_addr(attr.addr(), attr.size()))
|
||||
if (!vm::check_addr(attr.addr(), vm::page_readable, attr.size()))
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
@ -187,11 +187,11 @@ error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr<sys_
|
||||
attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE (TODO)
|
||||
attr->access_right = addr >> 28 == 0xdu ? SYS_MEMORY_ACCESS_RIGHT_PPU_THR : SYS_MEMORY_ACCESS_RIGHT_ANY;// (TODO)
|
||||
|
||||
if (vm::check_addr(addr, 1, vm::page_1m_size))
|
||||
if (vm::check_addr(addr, vm::page_1m_size))
|
||||
{
|
||||
attr->page_size = 0x100000;
|
||||
}
|
||||
else if (vm::check_addr(addr, 1, vm::page_64k_size))
|
||||
else if (vm::check_addr(addr, vm::page_64k_size))
|
||||
{
|
||||
attr->page_size = 0x10000;
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u32 io, u32 ea
|
||||
|
||||
for (u32 addr = ea, end = ea + size; addr < end; addr += 0x100000)
|
||||
{
|
||||
if (!vm::check_addr(addr, 1, vm::page_readable | (addr < 0x20000000 ? 0 : vm::page_1m_size)))
|
||||
if (!vm::check_addr(addr, vm::page_readable | (addr < 0x20000000 ? 0 : vm::page_1m_size)))
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ error_code sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwrit
|
||||
|
||||
std::string msg;
|
||||
|
||||
if (static_cast<s32>(len) > 0 && vm::check_addr(buf.addr(), len))
|
||||
if (static_cast<s32>(len) > 0 && vm::check_addr(buf.addr(), vm::page_readable, len))
|
||||
{
|
||||
msg.resize(len);
|
||||
|
||||
|
@ -641,7 +641,7 @@ bool gdb_thread::cmd_write_memory(gdb_cmd& cmd)
|
||||
u32 len = hex_to_u32(cmd.data.substr(s + 1, s2 - s - 1));
|
||||
const char* data_ptr = (cmd.data.c_str()) + s2 + 1;
|
||||
for (u32 i = 0; i < len; ++i) {
|
||||
if (vm::check_addr(addr + i, 1, vm::page_writable)) {
|
||||
if (vm::check_addr(addr + i, vm::page_writable)) {
|
||||
u8 val;
|
||||
int res = sscanf_s(data_ptr, "%02hhX", &val);
|
||||
if (!res) {
|
||||
|
@ -77,13 +77,6 @@ namespace vm
|
||||
// Memory range lock slots (sparse atomics)
|
||||
atomic_t<u64, 64> g_range_lock_set[64]{};
|
||||
|
||||
// Page information
|
||||
struct memory_page
|
||||
{
|
||||
// Memory flags
|
||||
atomic_t<u8> flags;
|
||||
};
|
||||
|
||||
// Memory pages
|
||||
std::array<memory_page, 0x100000000 / 4096> g_pages{};
|
||||
|
||||
@ -192,7 +185,7 @@ namespace vm
|
||||
{
|
||||
const u64 new_lock_val = g_range_lock.load();
|
||||
|
||||
if (!new_lock_val || new_lock_val == lock_val) [[likely]]
|
||||
if (vm::check_addr(begin, vm::page_readable, size) && (!new_lock_val || new_lock_val == lock_val)) [[likely]]
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -960,10 +953,15 @@ namespace vm
|
||||
return size;
|
||||
}
|
||||
|
||||
bool check_addr(u32 addr, u32 size, u8 flags)
|
||||
bool check_addr(u32 addr, u8 flags, u32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overflow checking
|
||||
if (addr + size < addr && (addr + size) != 0)
|
||||
if (0x10000'0000ull - addr < size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -971,12 +969,28 @@ namespace vm
|
||||
// Always check this flag
|
||||
flags |= page_allocated;
|
||||
|
||||
for (u32 i = addr / 4096, max = (addr + size - 1) / 4096; i <= max; i++)
|
||||
for (u32 i = addr / 4096, max = (addr + size - 1) / 4096; i <= max;)
|
||||
{
|
||||
if ((g_pages[i].flags & flags) != flags) [[unlikely]]
|
||||
auto state = +g_pages[i].flags;
|
||||
|
||||
if (~state & flags) [[unlikely]]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state & page_1m_size)
|
||||
{
|
||||
i = ::align(i + 1, 0x100000 / 4096);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state & page_64k_size)
|
||||
{
|
||||
i = ::align(i + 1, 0x10000 / 4096);
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1534,12 +1548,7 @@ namespace vm
|
||||
{
|
||||
vm::reader_lock lock;
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (vm::check_addr(addr, size, is_write ? page_writable : page_readable))
|
||||
if (vm::check_addr(addr, is_write ? page_writable : page_readable, size))
|
||||
{
|
||||
void* src = vm::g_sudo_addr + addr;
|
||||
void* dst = ptr;
|
||||
|
@ -52,11 +52,32 @@ namespace vm
|
||||
// Address type
|
||||
enum addr_t : u32 {};
|
||||
|
||||
// Page information
|
||||
struct memory_page
|
||||
{
|
||||
// Memory flags
|
||||
atomic_t<u8> flags;
|
||||
};
|
||||
|
||||
// Change memory protection of specified memory region
|
||||
bool page_protect(u32 addr, u32 size, u8 flags_test = 0, u8 flags_set = 0, u8 flags_clear = 0);
|
||||
|
||||
// Check flags for specified memory range (unsafe)
|
||||
bool check_addr(u32 addr, u32 size = 1, u8 flags = page_readable);
|
||||
bool check_addr(u32 addr, u8 flags, u32 size);
|
||||
|
||||
template <u32 Size = 1>
|
||||
bool check_addr(u32 addr, u8 flags = page_readable)
|
||||
{
|
||||
extern std::array<memory_page, 0x100000000 / 4096> g_pages;
|
||||
|
||||
if (Size - 1 >= 4095u || Size & (Size - 1) || addr % Size)
|
||||
{
|
||||
// TODO
|
||||
return check_addr(addr, flags, Size);
|
||||
}
|
||||
|
||||
return !(~g_pages[addr / 4096].flags & (flags | page_allocated));
|
||||
}
|
||||
|
||||
// Search and map memory in specified memory location (min alignment is 0x10000)
|
||||
u32 alloc(u32 size, memory_location_t location, u32 align = 0x10000);
|
||||
|
@ -52,6 +52,13 @@ namespace vm
|
||||
// Old-style conditional constexpr
|
||||
const u32 size = Size ? Size : _size;
|
||||
|
||||
if (size <= 4096u && !((begin | size) & (size - 1)) ? !vm::check_addr(begin) : !vm::check_addr(begin, vm::page_readable, size))
|
||||
{
|
||||
range_lock->release(0);
|
||||
range_lock_internal(range_lock, begin, _size);
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 lock_val = g_range_lock.load();
|
||||
const u64 is_share = g_shmem[begin >> 16].load();
|
||||
|
||||
|
@ -2115,7 +2115,7 @@ namespace rsx
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!vm::check_addr(write_end, (heuristic_end - write_end), vm::page_info_t::page_allocated))
|
||||
if (!vm::check_addr(write_end, vm::page_readable, (heuristic_end - write_end)))
|
||||
{
|
||||
// Enforce strict allocation size!
|
||||
return false;
|
||||
|
@ -96,7 +96,7 @@ void breakpoint_list::HandleBreakpointRequest(u32 loc)
|
||||
{
|
||||
const auto cpu = this->cpu.lock();
|
||||
|
||||
if (cpu->id_type() == 1 && vm::check_addr(loc, 1, vm::page_allocated | vm::page_executable))
|
||||
if (cpu->id_type() == 1 && vm::check_addr(loc, vm::page_allocated | vm::page_executable))
|
||||
{
|
||||
AddBreakpoint(loc);
|
||||
}
|
||||
|
@ -325,7 +325,7 @@ std::vector<u32> cheat_engine::search(const T value, const std::vector<u32>& to_
|
||||
{
|
||||
for (const auto& off : to_filter)
|
||||
{
|
||||
if (vm::check_addr(off, sizeof(T)))
|
||||
if (vm::check_addr<sizeof(T)>(off))
|
||||
{
|
||||
if (*vm::get_super_ptr<T>(off) == value_swapped)
|
||||
results.push_back(off);
|
||||
@ -364,7 +364,7 @@ T cheat_engine::get_value(const u32 offset, bool& success)
|
||||
|
||||
return cpu_thread::suspend_all(nullptr, {}, [&]() -> T
|
||||
{
|
||||
if (!vm::check_addr(offset, sizeof(T)))
|
||||
if (!vm::check_addr<sizeof(T)>(offset))
|
||||
{
|
||||
success = false;
|
||||
return 0;
|
||||
@ -381,21 +381,21 @@ bool cheat_engine::set_value(const u32 offset, const T value)
|
||||
if (Emu.IsStopped())
|
||||
return false;
|
||||
|
||||
if (!vm::check_addr(offset, sizeof(T)))
|
||||
if (!vm::check_addr<sizeof(T)>(offset))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return cpu_thread::suspend_all(nullptr, {}, [&]
|
||||
{
|
||||
if (!vm::check_addr(offset, sizeof(T)))
|
||||
if (!vm::check_addr<sizeof(T)>(offset))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*vm::get_super_ptr<T>(offset) = value;
|
||||
|
||||
const bool exec_code_at_start = vm::check_addr(offset, 1, vm::page_executable);
|
||||
const bool exec_code_at_start = vm::check_addr(offset, vm::page_executable);
|
||||
const bool exec_code_at_end = [&]()
|
||||
{
|
||||
if constexpr (sizeof(T) == 1)
|
||||
@ -404,7 +404,7 @@ bool cheat_engine::set_value(const u32 offset, const T value)
|
||||
}
|
||||
else
|
||||
{
|
||||
return vm::check_addr(offset + sizeof(T) - 1, 1, vm::page_executable);
|
||||
return vm::check_addr(offset + sizeof(T) - 1, vm::page_executable);
|
||||
}
|
||||
}();
|
||||
|
||||
|
@ -126,14 +126,14 @@ void debugger_list::ShowAddress(u32 addr, bool force)
|
||||
item(i)->setBackground(default_background);
|
||||
}
|
||||
|
||||
if (!is_spu && !vm::check_addr(pc, 4))
|
||||
if (!is_spu && !vm::check_addr(pc))
|
||||
{
|
||||
item(i)->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] ?? ?? ?? ??:", pc)));
|
||||
count = 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_spu && !vm::check_addr(pc, 4, vm::page_executable))
|
||||
if (!is_spu && !vm::check_addr(pc, vm::page_executable))
|
||||
{
|
||||
const u32 data = *vm::get_super_ptr<atomic_be_t<u32>>(pc);
|
||||
item(i)->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] %02x %02x %02x %02x:", pc,
|
||||
|
@ -514,7 +514,7 @@ void kernel_explorer::Update()
|
||||
|
||||
if (!pspurs)
|
||||
{
|
||||
if (arg < UINT32_MAX && arg % 0x80 == 0 && vm::check_addr(arg, pspurs.size()))
|
||||
if (arg < UINT32_MAX && arg % 0x80 == 0 && vm::check_addr(arg, vm::page_readable, pspurs.size()))
|
||||
{
|
||||
pspurs.set(static_cast<u32>(arg));
|
||||
}
|
||||
|
@ -324,7 +324,7 @@ void register_editor_dialog::OnOkay(const std::shared_ptr<cpu_thread>& _cpu)
|
||||
if (reg == PPU_CR) ppu.cr.unpack(reg_value);
|
||||
else if (reg == PPU_VRSAVE) ppu.vrsave = reg_value;
|
||||
else if (reg == PPU_PRIO && !sys_ppu_thread_set_priority(ppu, ppu.id, reg_value)) {}
|
||||
else if (reg == PC && reg_value % 4 == 0 && vm::check_addr(reg_value, 4, vm::page_executable)) ppu.cia = reg_value & -4;
|
||||
else if (reg == PC && reg_value % 4 == 0 && vm::check_addr(reg_value, vm::page_executable)) ppu.cia = reg_value & -4;
|
||||
else ok = false;
|
||||
if (ok) return;
|
||||
}
|
||||
|
@ -662,7 +662,7 @@ void rsx_debugger::GetBuffers()
|
||||
const u32 width = buffers[bufferId].width;
|
||||
const u32 height = buffers[bufferId].height;
|
||||
|
||||
if(!vm::check_addr(RSXbuffer_addr, width * height * 4))
|
||||
if (!vm::check_addr(RSXbuffer_addr, vm::page_readable, width * height * 4))
|
||||
continue;
|
||||
|
||||
const auto RSXbuffer = vm::get_super_ptr<const u8>(RSXbuffer_addr);
|
||||
@ -908,7 +908,7 @@ void rsx_debugger::SetPC(const uint pc)
|
||||
|
||||
void rsx_debugger::PerformJump(u32 address)
|
||||
{
|
||||
if (!vm::check_addr(address, 4))
|
||||
if (!vm::check_addr(address))
|
||||
return;
|
||||
|
||||
u32 cmd = *vm::get_super_ptr<u32>(address);
|
||||
|
Loading…
Reference in New Issue
Block a user