| 1218 | } |
| 1219 | |
| 1220 | bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noexcept |
| 1221 | { |
| 1222 | g_tls_fault_all++; |
| 1223 | |
| 1224 | const auto cpu = get_current_cpu_thread(); |
| 1225 | |
| 1226 | struct spu_unsavable |
| 1227 | { |
| 1228 | spu_thread* _spu; |
| 1229 | |
| 1230 | spu_unsavable(cpu_thread* cpu) noexcept |
| 1231 | : _spu(cpu ? cpu->try_get<spu_thread>() : nullptr) |
| 1232 | { |
| 1233 | if (_spu) |
| 1234 | { |
| 1235 | if (_spu->unsavable) |
| 1236 | { |
| 1237 | _spu = nullptr; |
| 1238 | } |
| 1239 | else |
| 1240 | { |
| 1241 | // Must not be saved inside access violation handler because it is unpredictable |
| 1242 | _spu->unsavable = true; |
| 1243 | } |
| 1244 | } |
| 1245 | } |
| 1246 | |
| 1247 | ~spu_unsavable() noexcept |
| 1248 | { |
| 1249 | if (_spu) |
| 1250 | { |
| 1251 | _spu->unsavable = false; |
| 1252 | } |
| 1253 | } |
| 1254 | } spu_protection{cpu}; |
| 1255 | |
| 1256 | if (addr < RAW_SPU_BASE_ADDR && vm::check_addr(addr) && rsx::g_access_violation_handler) |
| 1257 | { |
| 1258 | bool state_changed = false; |
| 1259 | |
| 1260 | if (cpu) |
| 1261 | { |
| 1262 | state_changed = vm::temporary_unlock(*cpu); |
| 1263 | } |
| 1264 | |
| 1265 | bool handled = rsx::g_access_violation_handler(addr, is_writing); |
| 1266 | |
| 1267 | if (state_changed && (cpu->state += cpu_flag::temp, cpu->test_stopped())) |
| 1268 | { |
| 1269 | // |
| 1270 | } |
| 1271 | |
| 1272 | if (handled) |
| 1273 | { |
| 1274 | g_tls_fault_rsx++; |
| 1275 | return true; |
| 1276 | } |
| 1277 | } |
no test coverage detected