mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-02 19:13:36 +00:00
rsx: recover from FIFO parse errors
- Validate FIFO registers before access -- Validate the args ptr separate from the get ptr
This commit is contained in:
parent
ef822d785e
commit
34c2b8a55e
@ -403,6 +403,19 @@ namespace rsx
|
||||
continue;
|
||||
}
|
||||
|
||||
//Validate put and get registers
|
||||
//TODO: Who should handle graphics exceptions??
|
||||
const u32 get_address = RSXIOMem.RealAddr(get);
|
||||
|
||||
if (!get_address)
|
||||
{
|
||||
LOG_ERROR(RSX, "Invalid FIFO queue get/put registers found, get=0x%X, put=0x%X", get, put);
|
||||
|
||||
invalid_command_interrupt_raised = true;
|
||||
ctrl->get = put;
|
||||
continue;
|
||||
}
|
||||
|
||||
const u32 cmd = ReadIO32(get);
|
||||
const u32 count = (cmd >> 18) & 0x7ff;
|
||||
|
||||
@ -442,7 +455,20 @@ namespace rsx
|
||||
continue;
|
||||
}
|
||||
|
||||
auto args = vm::ptr<u32>::make((u32)RSXIOMem.RealAddr(get + 4));
|
||||
//Validate the args ptr if the command attempts to read from it
|
||||
const u32 args_address = RSXIOMem.RealAddr(get + 4);
|
||||
|
||||
if (!args_address && count)
|
||||
{
|
||||
LOG_ERROR(RSX, "Invalid FIFO queue args ptr found, get=0x%X, cmd=0x%X, count=%d", get, cmd, count);
|
||||
|
||||
invalid_command_interrupt_raised = true;
|
||||
ctrl->get = put;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto args = vm::ptr<u32>::make(args_address);
|
||||
invalid_command_interrupt_raised = false;
|
||||
|
||||
u32 first_cmd = (cmd & 0xfffc) >> 2;
|
||||
|
||||
@ -469,8 +495,18 @@ namespace rsx
|
||||
{
|
||||
method(this, reg, value);
|
||||
}
|
||||
|
||||
if (invalid_command_interrupt_raised)
|
||||
{
|
||||
//Ignore processing the rest of the chain
|
||||
ctrl->get = put;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid_command_interrupt_raised)
|
||||
continue;
|
||||
|
||||
ctrl->get = get + (count + 1) * 4;
|
||||
}
|
||||
}
|
||||
|
@ -232,6 +232,7 @@ namespace rsx
|
||||
|
||||
public:
|
||||
std::set<u32> m_used_gcm_commands;
|
||||
bool invalid_command_interrupt_raised = false;
|
||||
|
||||
protected:
|
||||
thread();
|
||||
|
@ -1000,7 +1000,12 @@ enum
|
||||
NV3089_IMAGE_IN_OFFSET = 0x0000C408 >> 2,
|
||||
NV3089_IMAGE_IN = 0x0000C40C >> 2,
|
||||
|
||||
GCM_FLIP_HEAD0 = 0X0000E920 >> 2,
|
||||
GCM_FLIP_HEAD1 = 0X0000E924 >> 2,
|
||||
GCM_PREPARE_DISPLAY_BUFFER_HEAD0 = 0X0000E940 >> 2, //0X940 + [HEAD << 2]
|
||||
GCM_PREPARE_DISPLAY_BUFFER_HEAD1 = 0X0000E944 >> 2,
|
||||
GCM_SET_USER_COMMAND = 0x0000EB00 >> 2,
|
||||
GCM_SET_USER_COMMAND2 = 0x0000EB04 >> 2,
|
||||
|
||||
GCM_FLIP_COMMAND = 0x0000FEAC >> 2
|
||||
};
|
||||
|
@ -29,9 +29,12 @@ namespace rsx
|
||||
|
||||
std::array<rsx_method_t, 0x10000 / 4> methods{};
|
||||
|
||||
[[noreturn]] void invalid_method(thread*, u32 _reg, u32 arg)
|
||||
void invalid_method(thread* rsx, u32 _reg, u32 arg)
|
||||
{
|
||||
fmt::throw_exception("Invalid RSX method 0x%x (arg=0x%x)" HERE, _reg << 2, arg);
|
||||
//Don't throw, gather information and ignore broken/garbage commands
|
||||
//TODO: Investigate why these commands are executed at all. (Heap corruption? Alignment padding?)
|
||||
LOG_ERROR(RSX, "Invalid RSX method 0x%x (arg=0x%x)" HERE, _reg << 2, arg);
|
||||
rsx->invalid_command_interrupt_raised = true;
|
||||
}
|
||||
|
||||
template<typename Type> struct vertex_data_type_from_element_type;
|
||||
@ -1244,6 +1247,10 @@ namespace rsx
|
||||
methods[NV3089_IMAGE_IN_OFFSET] = nullptr;
|
||||
methods[NV3089_IMAGE_IN] = nullptr;
|
||||
|
||||
//Some custom GCM methods
|
||||
methods[GCM_PREPARE_DISPLAY_BUFFER_HEAD0] = nullptr;
|
||||
methods[GCM_PREPARE_DISPLAY_BUFFER_HEAD1] = nullptr;
|
||||
|
||||
bind_array<NV4097_SET_ANISO_SPREAD, 1, 16, nullptr>();
|
||||
bind_array<NV4097_SET_VERTEX_TEXTURE_OFFSET, 1, 8 * 4, nullptr>();
|
||||
bind_array<NV4097_SET_VERTEX_DATA_SCALED4S_M, 1, 32, nullptr>();
|
||||
@ -1333,7 +1340,10 @@ namespace rsx
|
||||
|
||||
// custom methods
|
||||
bind<GCM_FLIP_COMMAND, flip_command>();
|
||||
bind<GCM_FLIP_HEAD0, flip_command>();
|
||||
bind<GCM_FLIP_HEAD1, flip_command>();
|
||||
bind<GCM_SET_USER_COMMAND, user_command>();
|
||||
bind<GCM_SET_USER_COMMAND2, user_command>();
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
Loading…
x
Reference in New Issue
Block a user