vm: Fix possible IDM deadlock with Page Fault Notifications (partial)

This commit is contained in:
Eladash 2020-04-02 22:18:23 +03:00 committed by Ani
commit bb950cbb3b
6 changed files with 60 additions and 43 deletions

View file

@ -24,13 +24,15 @@ error_code sys_cond_create(ppu_thread& ppu, vm::ptr<u32> cond_id, u32 mutex_id,
return CELL_ESRCH; return CELL_ESRCH;
} }
if (auto error = lv2_obj::create<lv2_cond>(attr->pshared, attr->ipc_key, attr->flags, [&] const auto _attr = *attr;
if (auto error = lv2_obj::create<lv2_cond>(_attr.pshared, _attr.ipc_key, _attr.flags, [&]
{ {
return std::make_shared<lv2_cond>( return std::make_shared<lv2_cond>(
attr->pshared, _attr.pshared,
attr->flags, _attr.flags,
attr->ipc_key, _attr.ipc_key,
attr->name_u64, _attr.name_u64,
std::move(mutex)); std::move(mutex));
})) }))
{ {

View file

@ -24,7 +24,9 @@ error_code sys_event_flag_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<sys_e
return CELL_EFAULT; return CELL_EFAULT;
} }
const u32 protocol = attr->protocol; const auto _attr = *attr;
const u32 protocol = _attr.protocol;
if (protocol != SYS_SYNC_FIFO && protocol != SYS_SYNC_PRIORITY) if (protocol != SYS_SYNC_FIFO && protocol != SYS_SYNC_PRIORITY)
{ {
@ -32,7 +34,7 @@ error_code sys_event_flag_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<sys_e
return CELL_EINVAL; return CELL_EINVAL;
} }
const u32 type = attr->type; const u32 type = _attr.type;
if (type != SYS_SYNC_WAITER_SINGLE && type != SYS_SYNC_WAITER_MULTIPLE) if (type != SYS_SYNC_WAITER_SINGLE && type != SYS_SYNC_WAITER_MULTIPLE)
{ {
@ -40,15 +42,15 @@ error_code sys_event_flag_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<sys_e
return CELL_EINVAL; return CELL_EINVAL;
} }
if (auto error = lv2_obj::create<lv2_event_flag>(attr->pshared, attr->ipc_key, attr->flags, [&] if (auto error = lv2_obj::create<lv2_event_flag>(_attr.pshared, _attr.ipc_key, _attr.flags, [&]
{ {
return std::make_shared<lv2_event_flag>( return std::make_shared<lv2_event_flag>(
attr->protocol, _attr.protocol,
attr->pshared, _attr.pshared,
attr->ipc_key, _attr.ipc_key,
attr->flags, _attr.flags,
attr->type, _attr.type,
attr->name_u64, _attr.name_u64,
init); init);
})) }))
{ {

View file

@ -22,7 +22,9 @@ error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_
return CELL_EFAULT; return CELL_EFAULT;
} }
switch (attr->protocol) const auto _attr = *attr;
switch (_attr.protocol)
{ {
case SYS_SYNC_FIFO: break; case SYS_SYNC_FIFO: break;
case SYS_SYNC_PRIORITY: break; case SYS_SYNC_PRIORITY: break;
@ -31,37 +33,37 @@ error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_
break; break;
default: default:
{ {
sys_mutex.error("sys_mutex_create(): unknown protocol (0x%x)", attr->protocol); sys_mutex.error("sys_mutex_create(): unknown protocol (0x%x)", _attr.protocol);
return CELL_EINVAL; return CELL_EINVAL;
} }
} }
switch (attr->recursive) switch (_attr.recursive)
{ {
case SYS_SYNC_RECURSIVE: break; case SYS_SYNC_RECURSIVE: break;
case SYS_SYNC_NOT_RECURSIVE: break; case SYS_SYNC_NOT_RECURSIVE: break;
default: default:
{ {
sys_mutex.error("sys_mutex_create(): unknown recursive (0x%x)", attr->recursive); sys_mutex.error("sys_mutex_create(): unknown recursive (0x%x)", _attr.recursive);
return CELL_EINVAL; return CELL_EINVAL;
} }
} }
if (attr->adaptive != SYS_SYNC_NOT_ADAPTIVE) if (_attr.adaptive != SYS_SYNC_NOT_ADAPTIVE)
{ {
sys_mutex.todo("sys_mutex_create(): unexpected adaptive (0x%x)", attr->adaptive); sys_mutex.todo("sys_mutex_create(): unexpected adaptive (0x%x)", _attr.adaptive);
} }
if (auto error = lv2_obj::create<lv2_mutex>(attr->pshared, attr->ipc_key, attr->flags, [&]() if (auto error = lv2_obj::create<lv2_mutex>(_attr.pshared, _attr.ipc_key, _attr.flags, [&]()
{ {
return std::make_shared<lv2_mutex>( return std::make_shared<lv2_mutex>(
attr->protocol, _attr.protocol,
attr->recursive, _attr.recursive,
attr->pshared, _attr.pshared,
attr->adaptive, _attr.adaptive,
attr->ipc_key, _attr.ipc_key,
attr->flags, _attr.flags,
attr->name_u64); _attr.name_u64);
})) }))
{ {
return error; return error;

View file

@ -364,6 +364,7 @@ error_code _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_par
} }
const ppu_func_opd_t entry = param->entry.opd(); const ppu_func_opd_t entry = param->entry.opd();
const u32 tls = param->tls;
// Clean some detached thread (hack) // Clean some detached thread (hack)
g_fxo->get<ppu_thread_cleaner>()->clean(0); g_fxo->get<ppu_thread_cleaner>()->clean(0);
@ -389,6 +390,13 @@ error_code _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_par
std::string ppu_name; std::string ppu_name;
if (threadname)
{
constexpr u32 max_size = 27; // max size including null terminator
const auto pname = threadname.get_ptr();
ppu_name.assign(pname, std::find(pname, pname + max_size, '\0'));
}
const u32 tid = idm::import<named_thread<ppu_thread>>([&]() const u32 tid = idm::import<named_thread<ppu_thread>>([&]()
{ {
const u32 tid = idm::last_id(); const u32 tid = idm::last_id();
@ -397,10 +405,6 @@ error_code _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_par
if (threadname) if (threadname)
{ {
constexpr u32 max_size = 27; // max size including null terminator
const auto pname = threadname.get_ptr();
ppu_name.assign(pname, std::find(pname, pname + max_size, '\0'));
if (!ppu_name.empty()) if (!ppu_name.empty())
{ {
fmt::append(full_name, " (%s)", ppu_name); fmt::append(full_name, " (%s)", ppu_name);
@ -410,7 +414,7 @@ error_code _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_par
ppu_thread_params p; ppu_thread_params p;
p.stack_addr = stack_base; p.stack_addr = stack_base;
p.stack_size = stack_size; p.stack_size = stack_size;
p.tls_addr = param->tls; p.tls_addr = tls;
p.entry = entry; p.entry = entry;
p.arg0 = arg; p.arg0 = arg;
p.arg1 = unk; p.arg1 = unk;
@ -426,7 +430,7 @@ error_code _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_par
} }
*thread_id = tid; *thread_id = tid;
sys_ppu_thread.warning(u8"_sys_ppu_thread_create(): Thread “%s” created (id=0x%x, func=*0x%x, rtoc=0x%x)", ppu_name, tid, entry.addr, entry.rtoc); sys_ppu_thread.warning(u8"_sys_ppu_thread_create(): Thread “%s” created (id=0x%x, func=*0x%x, rtoc=0x%x, user-tls=0x%x)", ppu_name, tid, entry.addr, entry.rtoc, tls);
return CELL_OK; return CELL_OK;
} }

View file

@ -22,7 +22,9 @@ error_code sys_rwlock_create(ppu_thread& ppu, vm::ptr<u32> rw_lock_id, vm::ptr<s
return CELL_EFAULT; return CELL_EFAULT;
} }
const u32 protocol = attr->protocol; const auto _attr = *attr;
const u32 protocol = _attr.protocol;
if (protocol == SYS_SYNC_PRIORITY_INHERIT) if (protocol == SYS_SYNC_PRIORITY_INHERIT)
sys_rwlock.todo("sys_rwlock_create(): SYS_SYNC_PRIORITY_INHERIT"); sys_rwlock.todo("sys_rwlock_create(): SYS_SYNC_PRIORITY_INHERIT");
@ -33,9 +35,9 @@ error_code sys_rwlock_create(ppu_thread& ppu, vm::ptr<u32> rw_lock_id, vm::ptr<s
return CELL_EINVAL; return CELL_EINVAL;
} }
if (auto error = lv2_obj::create<lv2_rwlock>(attr->pshared, attr->ipc_key, attr->flags, [&] if (auto error = lv2_obj::create<lv2_rwlock>(_attr.pshared, _attr.ipc_key, _attr.flags, [&]
{ {
return std::make_shared<lv2_rwlock>(protocol, attr->pshared, attr->ipc_key, attr->flags, attr->name_u64); return std::make_shared<lv2_rwlock>(protocol, _attr.pshared, _attr.ipc_key, _attr.flags, _attr.name_u64);
})) }))
{ {
return error; return error;

View file

@ -28,7 +28,9 @@ error_code sys_semaphore_create(ppu_thread& ppu, vm::ptr<u32> sem_id, vm::ptr<sy
return CELL_EINVAL; return CELL_EINVAL;
} }
const u32 protocol = attr->protocol; const auto _attr = *attr;
const u32 protocol = _attr.protocol;
if (protocol != SYS_SYNC_FIFO && protocol != SYS_SYNC_PRIORITY) if (protocol != SYS_SYNC_FIFO && protocol != SYS_SYNC_PRIORITY)
{ {
@ -36,9 +38,9 @@ error_code sys_semaphore_create(ppu_thread& ppu, vm::ptr<u32> sem_id, vm::ptr<sy
return CELL_EINVAL; return CELL_EINVAL;
} }
if (auto error = lv2_obj::create<lv2_sema>(attr->pshared, attr->ipc_key, attr->flags, [&] if (auto error = lv2_obj::create<lv2_sema>(_attr.pshared, _attr.ipc_key, _attr.flags, [&]
{ {
return std::make_shared<lv2_sema>(protocol, attr->pshared, attr->ipc_key, attr->flags, attr->name_u64, max_val, initial_val); return std::make_shared<lv2_sema>(protocol, _attr.pshared, _attr.ipc_key, _attr.flags, _attr.name_u64, max_val, initial_val);
})) }))
{ {
return error; return error;
@ -268,13 +270,16 @@ error_code sys_semaphore_get_value(ppu_thread& ppu, u32 sem_id, vm::ptr<s32> cou
return CELL_EFAULT; return CELL_EFAULT;
} }
if (!idm::check<lv2_obj, lv2_sema>(sem_id, [=](lv2_sema& sema) const auto sema = idm::check<lv2_obj, lv2_sema>(sem_id, [](lv2_sema& sema)
{ {
*count = std::max<s32>(0, sema.val); return std::max<s32>(0, sema.val);
})) });
if (!sema)
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
*count = sema.ret;
return CELL_OK; return CELL_OK;
} }