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:
kd-11 2017-03-21 14:58:25 +03:00
parent ef822d785e
commit 34c2b8a55e
4 changed files with 55 additions and 3 deletions

View File

@ -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;
}
}

View File

@ -232,6 +232,7 @@ namespace rsx
public:
std::set<u32> m_used_gcm_commands;
bool invalid_command_interrupt_raised = false;
protected:
thread();

View File

@ -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
};

View File

@ -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;
}();