Merge branch 'RPCS3:master' into uruntime

This commit is contained in:
Escary 2025-04-07 16:45:03 +01:00 committed by GitHub
commit c5a63d5cf8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 104 additions and 20 deletions

View file

@ -502,7 +502,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
if (!cond || !mutex)
{
return CELL_ESRCH;
return { CELL_ESRCH, fmt::format("lwmutex_id: 0x%x, lwcond_id: 0x%x", lwmutex_id, lwcond_id) };
}
if (ppu.state & cpu_flag::again)

View file

@ -183,7 +183,12 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
if (!mutex)
{
return CELL_ESRCH;
if (lwmutex_id >> 24 == lv2_lwmutex::id_base >> 24)
{
return { CELL_ESRCH, lwmutex_id };
}
return { CELL_ESRCH, "Invalid ID" };
}
if (mutex.ret)
@ -313,7 +318,12 @@ error_code _sys_lwmutex_trylock(ppu_thread& ppu, u32 lwmutex_id)
if (!mutex)
{
return CELL_ESRCH;
if (lwmutex_id >> 24 == lv2_lwmutex::id_base >> 24)
{
return { CELL_ESRCH, lwmutex_id };
}
return { CELL_ESRCH, "Invalid ID" };
}
if (!mutex.ret)

View file

@ -388,19 +388,43 @@ struct spu_limits_t
SAVESTATE_INIT_POS(47);
bool check(const limits_data& init) const
bool check_valid(const limits_data& init) const
{
const u32 physical_spus_count = init.physical;
const u32 controllable_spu_count = init.controllable;
const u32 spu_limit = init.spu_limit != umax ? init.spu_limit : max_spu;
const u32 raw_limit = init.raw_limit != umax ? init.raw_limit : max_raw;
if (spu_limit + raw_limit > 6 || physical_spus_count > spu_limit || controllable_spu_count > spu_limit)
{
return false;
}
return true;
}
bool check_busy(const limits_data& init) const
{
u32 physical_spus_count = init.physical;
u32 raw_spu_count = init.raw_spu;
u32 controllable_spu_count = init.controllable;
u32 system_coop = init.controllable != 0 && init.physical != 0 ? 1 : 0;
const u32 spu_limit = init.spu_limit != umax ? init.spu_limit : max_spu;
const u32 raw_limit = init.raw_limit != umax ? init.raw_limit : max_raw;
idm::select<lv2_spu_group>([&](u32, lv2_spu_group& group)
{
if (group.has_scheduler_context)
if (group.type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
{
controllable_spu_count = std::max(controllable_spu_count, group.max_num);
system_coop++;
controllable_spu_count = std::max<u32>(controllable_spu_count, 1);
physical_spus_count += group.max_num - 1;
}
else if (group.has_scheduler_context)
{
controllable_spu_count = std::max<u32>(controllable_spu_count, group.max_num);
}
else
{
@ -410,11 +434,18 @@ struct spu_limits_t
raw_spu_count += spu_thread::g_raw_spu_ctr;
if (spu_limit + raw_limit > 6 || raw_spu_count > raw_limit || physical_spus_count >= spu_limit || physical_spus_count + controllable_spu_count > spu_limit)
// physical_spus_count >= spu_limit returns EBUSY, not EINVAL!
if (spu_limit + raw_limit > 6 || raw_spu_count > raw_limit || physical_spus_count >= spu_limit || physical_spus_count > spu_limit || controllable_spu_count > spu_limit)
{
return false;
}
if (system_coop > 1)
{
// Cannot have more than one SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM group at a time
return false;
}
return true;
}
};
@ -437,7 +468,7 @@ error_code sys_spu_initialize(ppu_thread& ppu, u32 max_usable_spu, u32 max_raw_s
std::lock_guard lock(limits.mutex);
if (!limits.check(limits_data{.spu_limit = max_usable_spu - max_raw_spu, .raw_limit = max_raw_spu}))
if (!limits.check_busy(limits_data{.spu_limit = max_usable_spu - max_raw_spu, .raw_limit = max_raw_spu}))
{
return CELL_EBUSY;
}
@ -845,23 +876,24 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
switch (type)
{
case 0x0:
case 0x4:
case 0x18:
case SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER:
case SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT:
{
break;
}
case 0x20:
case 0x22:
case 0x24:
case 0x26:
case SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM:
case (SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM | 0x2):
case (SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM | 0x4):
case (SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM | 0x6):
{
if (type == 0x22 || type == 0x26)
{
needs_root = true;
}
min_threads = 2; // That's what appears from reversing
// For a single thread that is being shared with system (the cooperative victim)
min_threads = 2;
break;
}
@ -901,7 +933,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
if (is_system_coop)
{
// Constant size, unknown what it means
// For a single thread that is being shared with system (the cooperative victim)
mem_size = SPU_LS_SIZE;
}
else if (type & SYS_SPU_THREAD_GROUP_TYPE_NON_CONTEXT)
@ -952,7 +984,29 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
std::unique_lock lock(limits.mutex);
if (!limits.check(use_scheduler ? limits_data{.controllable = num} : limits_data{.physical = num}))
limits_data group_limits{};
if (is_system_coop)
{
group_limits.controllable = 1;
group_limits.physical = num - 1;
}
else if (use_scheduler)
{
group_limits.controllable = num;
}
else
{
group_limits.physical = num;
}
if (!limits.check_valid(group_limits))
{
ct->free(mem_size);
return CELL_EINVAL;
}
if (!limits.check_busy(group_limits))
{
ct->free(mem_size);
return CELL_EBUSY;
@ -1135,6 +1189,11 @@ error_code sys_spu_thread_group_suspend(ppu_thread& ppu, u32 id)
return CELL_EINVAL;
}
if (group->type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
{
return CELL_EINVAL;
}
std::lock_guard lock(group->mutex);
CellError error;
@ -1218,6 +1277,11 @@ error_code sys_spu_thread_group_resume(ppu_thread& ppu, u32 id)
return CELL_EINVAL;
}
if (group->type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
{
return CELL_EINVAL;
}
struct notify_on_exit
{
usz index = umax;
@ -1565,6 +1629,11 @@ error_code sys_spu_thread_group_set_priority(ppu_thread& ppu, u32 id, s32 priori
return CELL_EINVAL;
}
if (group->type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
{
return CELL_EINVAL;
}
group->prio.atomic_op([&](std::common_type_t<decltype(lv2_spu_group::prio)>& prio)
{
prio.prio = priority;
@ -1592,6 +1661,11 @@ error_code sys_spu_thread_group_get_priority(ppu_thread& ppu, u32 id, vm::ptr<s3
{
*priority = 0;
}
else if (group->type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
{
// Regardless of the value being set in group creation
*priority = 15;
}
else
{
*priority = group->prio.load().prio;
@ -1751,7 +1825,7 @@ error_code sys_spu_thread_write_spu_mb(ppu_thread& ppu, u32 id, u32 value)
{
ppu.state += cpu_flag::wait;
sys_spu.warning("sys_spu_thread_write_spu_mb(id=0x%x, value=0x%x)", id, value);
sys_spu.trace("sys_spu_thread_write_spu_mb(id=0x%x, value=0x%x)", id, value);
const auto [thread, group] = lv2_spu_group::get_thread(id);
@ -2275,7 +2349,7 @@ error_code sys_raw_spu_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<void> at
std::lock_guard lock(limits.mutex);
if (!limits.check(limits_data{.raw_spu = 1}))
if (!limits.check_busy(limits_data{.raw_spu = 1}))
{
return CELL_EAGAIN;
}
@ -2331,7 +2405,7 @@ error_code sys_isolated_spu_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<voi
std::lock_guard lock(limits.mutex);
if (!limits.check(limits_data{.raw_spu = 1}))
if (!limits.check_busy(limits_data{.raw_spu = 1}))
{
return CELL_EAGAIN;
}