diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 2d1f8d0cc7..1f59aad125 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -23,6 +23,7 @@ #include "sys_timer.h" #include "sys_trace.h" #include "sys_fs.h" +#include "sys_spu.h" @@ -69,7 +70,7 @@ s32 sys_process_get_number_of_object(u32 object, vm::ptr nump) case SYS_EVENT_QUEUE_OBJECT: *nump = idm_get_count(); break; case SYS_EVENT_PORT_OBJECT: *nump = idm_get_count(); break; case SYS_TRACE_OBJECT: sys_process.error("sys_process_get_number_of_object: object = SYS_TRACE_OBJECT"); *nump = 0; break; - case SYS_SPUIMAGE_OBJECT: fmt::throw_exception("SYS_SPUIMAGE_OBJECT" HERE); + case SYS_SPUIMAGE_OBJECT: *nump = idm_get_count(); break; case SYS_PRX_OBJECT: *nump = idm_get_count(); break; case SYS_SPUPORT_OBJECT: fmt::throw_exception("SYS_SPUPORT_OBJECT" HERE); case SYS_OVERLAY_OBJECT: *nump = idm_get_count(); break; @@ -117,7 +118,7 @@ s32 sys_process_get_id(u32 object, vm::ptr buffer, u32 size, vm::ptr s case SYS_EVENT_QUEUE_OBJECT: idm_get_set(objects); break; case SYS_EVENT_PORT_OBJECT: idm_get_set(objects); break; case SYS_TRACE_OBJECT: fmt::throw_exception("SYS_TRACE_OBJECT" HERE); - case SYS_SPUIMAGE_OBJECT: fmt::throw_exception("SYS_SPUIMAGE_OBJECT" HERE); + case SYS_SPUIMAGE_OBJECT: idm_get_set(objects); break; case SYS_PRX_OBJECT: idm_get_set(objects); break; case SYS_SPUPORT_OBJECT: fmt::throw_exception("SYS_SPUPORT_OBJECT" HERE); case SYS_OVERLAY_OBJECT: idm_get_set(objects); break; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 96b2bf4a10..685518c72f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -43,12 +43,15 @@ void sys_spu_image::load(const fs::file& stream) } type = SYS_SPU_IMAGE_TYPE_KERNEL; - entry_point = obj.header.e_entry; + nsegs = sys_spu_image::get_nsegs(obj.progs); const u32 mem_size = nsegs * sizeof(sys_spu_segment) + ::size32(stream); segs = vm::cast(vm::alloc(mem_size, vm::main)); + // Write ID and save entry + entry_point = idm::make(+obj.header.e_entry); + const u32 src = segs.addr() + nsegs * sizeof(sys_spu_segment); stream.seek(0); @@ -158,7 +161,19 @@ error_code _sys_spu_image_get_information(ppu_thread& ppu, vm::ptrentry_point; + if (img->type != SYS_SPU_IMAGE_TYPE_KERNEL) + { + return CELL_EINVAL; + } + + const auto image = idm::get(img->entry_point); + + if (!image) + { + return CELL_ESRCH; + } + + *entry_point = image->e_entry; *nsegs = img->nsegs; return CELL_OK; } @@ -178,7 +193,6 @@ error_code sys_spu_image_open(ppu_thread& ppu, vm::ptr img, vm::c } img->load(elf_file); - return CELL_OK; } @@ -198,6 +212,16 @@ error_code _sys_spu_image_close(ppu_thread& ppu, vm::ptr img) sys_spu.warning("_sys_spu_image_close(img=*0x%x)", img); + if (img->type != SYS_SPU_IMAGE_TYPE_KERNEL) + { + return CELL_EINVAL; + } + + if (!idm::remove(img->entry_point)) + { + return CELL_ESRCH; + } + vm::dealloc(img->segs.addr(), vm::main); return CELL_OK; } @@ -236,11 +260,31 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g return CELL_EINVAL; } + if (img->type != SYS_SPU_IMAGE_TYPE_KERNEL && img->type != SYS_SPU_IMAGE_TYPE_USER) + { + return CELL_EINVAL; + } + if (group->threads[spu_num] || group->run_state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED) { return CELL_EBUSY; } + sys_spu_image image = *img; + + if (img->type == SYS_SPU_IMAGE_TYPE_KERNEL) + { + const auto handle = idm::get(img->entry_point); + + if (!handle) + { + return CELL_ESRCH; + } + + // Save actual entry point + image.entry_point = handle->e_entry; + } + if (u32 option = attr->option) { sys_spu.todo("Unimplemented SPU Thread options (0x%x)", option); @@ -266,7 +310,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g *thread = tid; group->args[spu_num] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4}; - group->imgs[spu_num] = std::make_pair(*img, std::vector()); + group->imgs[spu_num] = std::make_pair(image, std::vector()); group->imgs[spu_num].second.assign(img->segs.get_ptr(), img->segs.get_ptr() + img->nsegs); if (++group->init == group->max_num) diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 65c48df474..3704d5e8d8 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -1,5 +1,6 @@ #pragma once +#include "sys_sync.h" #include "sys_event.h" #include "Emu/Cell/SPUThread.h" @@ -112,7 +113,7 @@ enum : u32 struct sys_spu_image { be_t type; // user, kernel - be_t entry_point; + be_t entry_point; // Note: in kernel mode it's used to store id vm::bptr segs; be_t nsegs; @@ -210,6 +211,18 @@ enum : u32 SYS_SPU_IMAGE_DIRECT = 1, }; +struct lv2_spu_image : lv2_obj +{ + static const u32 id_base = 0x22000000; + + const u32 e_entry; + + lv2_spu_image(u32 entry) + : e_entry(entry) + { + } +}; + struct lv2_spu_group { static const u32 id_base = 0x04000100;