mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-12 09:48:37 +12: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
4 changed files with 55 additions and 3 deletions
|
@ -403,6 +403,19 @@ namespace rsx
|
||||||
continue;
|
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 cmd = ReadIO32(get);
|
||||||
const u32 count = (cmd >> 18) & 0x7ff;
|
const u32 count = (cmd >> 18) & 0x7ff;
|
||||||
|
|
||||||
|
@ -442,7 +455,20 @@ namespace rsx
|
||||||
continue;
|
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;
|
u32 first_cmd = (cmd & 0xfffc) >> 2;
|
||||||
|
|
||||||
|
@ -469,7 +495,17 @@ namespace rsx
|
||||||
{
|
{
|
||||||
method(this, reg, value);
|
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;
|
ctrl->get = get + (count + 1) * 4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,6 +232,7 @@ namespace rsx
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::set<u32> m_used_gcm_commands;
|
std::set<u32> m_used_gcm_commands;
|
||||||
|
bool invalid_command_interrupt_raised = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
thread();
|
thread();
|
||||||
|
|
|
@ -1000,7 +1000,12 @@ enum
|
||||||
NV3089_IMAGE_IN_OFFSET = 0x0000C408 >> 2,
|
NV3089_IMAGE_IN_OFFSET = 0x0000C408 >> 2,
|
||||||
NV3089_IMAGE_IN = 0x0000C40C >> 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_COMMAND = 0x0000EB00 >> 2,
|
||||||
|
GCM_SET_USER_COMMAND2 = 0x0000EB04 >> 2,
|
||||||
|
|
||||||
GCM_FLIP_COMMAND = 0x0000FEAC >> 2
|
GCM_FLIP_COMMAND = 0x0000FEAC >> 2
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,9 +29,12 @@ namespace rsx
|
||||||
|
|
||||||
std::array<rsx_method_t, 0x10000 / 4> methods{};
|
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;
|
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_OFFSET] = nullptr;
|
||||||
methods[NV3089_IMAGE_IN] = 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_ANISO_SPREAD, 1, 16, nullptr>();
|
||||||
bind_array<NV4097_SET_VERTEX_TEXTURE_OFFSET, 1, 8 * 4, nullptr>();
|
bind_array<NV4097_SET_VERTEX_TEXTURE_OFFSET, 1, 8 * 4, nullptr>();
|
||||||
bind_array<NV4097_SET_VERTEX_DATA_SCALED4S_M, 1, 32, nullptr>();
|
bind_array<NV4097_SET_VERTEX_DATA_SCALED4S_M, 1, 32, nullptr>();
|
||||||
|
@ -1333,7 +1340,10 @@ namespace rsx
|
||||||
|
|
||||||
// custom methods
|
// custom methods
|
||||||
bind<GCM_FLIP_COMMAND, flip_command>();
|
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_COMMAND, user_command>();
|
||||||
|
bind<GCM_SET_USER_COMMAND2, user_command>();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}();
|
}();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue