From 730e9cde8443ddefd143514f9ca13852fad2a41e Mon Sep 17 00:00:00 2001 From: eladash Date: Wed, 31 Oct 2018 04:40:04 +0200 Subject: [PATCH] sys_rsx: Improve allocations and error checks * allow sys_rsx_device_map to be called twice: in this case the DEVICE address retrived from the previous call returned * Add ENOMEM checks for sys_rsx_memory_allocate and sys_rsx_context_allocate * add EINVAL check for sys_rsx_context_allocate if memory handle is not found * Separate sys_rsx_device_map allocation from sys_rsx_context_allocate's * Implement sys_rsx_memory_free; used by cellGcmInit upon failure * Added context_id checks * Throw if sys_rsx_context_allocate was called twice. --- rpcs3/Emu/Cell/Modules/cellGcmSys.cpp | 10 +-- rpcs3/Emu/Cell/lv2/sys_rsx.cpp | 112 ++++++++++++++++++-------- rpcs3/Emu/Cell/lv2/sys_rsx.h | 14 ++-- rpcs3/Emu/Memory/vm.cpp | 1 + rpcs3/Emu/Memory/vm.h | 1 + rpcs3/Emu/RSX/RSXThread.cpp | 4 +- rpcs3/Emu/RSX/RSXThread.h | 2 +- rpcs3/Emu/RSX/rsx_methods.cpp | 2 +- 8 files changed, 96 insertions(+), 50 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 27aa9c16f1..cc23c7d870 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -389,11 +389,9 @@ s32 _cellGcmInitBody(ppu_thread& ppu, vm::pptr context, u32 gcm_cfg->current_config.coreFrequency = 500000000; // Create contexts - auto ctx_area = vm::find_map(0x10000000, 0x10000000, 0x403); - u32 rsx_ctxaddr = ctx_area ? ctx_area->addr : 0; - - if (!rsx_ctxaddr || vm::falloc(rsx_ctxaddr, 0x400000) != rsx_ctxaddr) - fmt::throw_exception("Failed to alloc rsx context."); + const auto area = vm::reserve_map(vm::rsx_context, 0, 0x10000000, 0x403); + const u32 rsx_ctxaddr = area ? area->alloc(0x400000) : 0; + verify(HERE), rsx_ctxaddr != 0; g_defaultCommandBufferBegin = ioAddress; g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024); @@ -429,7 +427,7 @@ s32 _cellGcmInitBody(ppu_thread& ppu, vm::pptr context, u32 render->intr_thread->state -= cpu_flag::stop; render->isHLE = true; render->label_addr = gcm_cfg->gcm_info.label_addr; - render->ctxt_addr = gcm_cfg->gcm_info.context_addr; + render->device_addr = gcm_cfg->gcm_info.context_addr; render->init(gcm_cfg->gcm_info.control_addr - 0x40); return CELL_OK; diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index 23af0bb3a7..1c73fbc6c1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -68,10 +68,14 @@ error_code sys_rsx_memory_allocate(vm::ptr mem_handle, vm::ptr mem_add { sys_rsx.warning("sys_rsx_memory_allocate(mem_handle=*0x%x, mem_addr=*0x%x, size=0x%x, flags=0x%llx, a5=0x%llx, a6=0x%llx, a7=0x%llx)", mem_handle, mem_addr, size, flags, a5, a6, a7); - *mem_handle = 0x5a5a5a5b; - *mem_addr = vm::falloc(rsx::constants::local_mem_base, size, vm::video); + if (u32 addr = vm::falloc(rsx::constants::local_mem_base, size, vm::video)) + { + *mem_addr = addr; + *mem_handle = 0x5a5a5a5b; + return CELL_OK; + } - return CELL_OK; + return CELL_ENOMEM; } /* @@ -80,7 +84,22 @@ error_code sys_rsx_memory_allocate(vm::ptr mem_handle, vm::ptr mem_add */ error_code sys_rsx_memory_free(u32 mem_handle) { - sys_rsx.todo("sys_rsx_memory_free(mem_handle=0x%x)", mem_handle); + sys_rsx.warning("sys_rsx_memory_free(mem_handle=0x%x)", mem_handle); + + if (!vm::check_addr(rsx::constants::local_mem_base)) + { + return CELL_ENOMEM; + } + + if (g_fxo->get()->context_base) + { + fmt::throw_exception("Attempting to dealloc rsx memory when the context is still being used" HERE); + } + + if (!vm::dealloc(rsx::constants::local_mem_base)) + { + return CELL_ENOMEM; + } return CELL_OK; } @@ -99,18 +118,32 @@ error_code sys_rsx_context_allocate(vm::ptr context_id, vm::ptr lpar_d sys_rsx.warning("sys_rsx_context_allocate(context_id=*0x%x, lpar_dma_control=*0x%x, lpar_driver_info=*0x%x, lpar_reports=*0x%x, mem_ctx=0x%llx, system_mode=0x%llx)", context_id, lpar_dma_control, lpar_driver_info, lpar_reports, mem_ctx, system_mode); - auto rsx_cfg = g_fxo->get(); - - if (!rsx_cfg->state) + if (!vm::check_addr(rsx::constants::local_mem_base)) { return CELL_EINVAL; } - *context_id = 0x55555555; + auto rsx_cfg = g_fxo->get(); - *lpar_dma_control = rsx_cfg->rsx_context_addr + 0x100000; - *lpar_driver_info = rsx_cfg->rsx_context_addr + 0x200000; - *lpar_reports = rsx_cfg->rsx_context_addr + 0x300000; + std::lock_guard lock(s_rsxmem_mtx); + + if (rsx_cfg->context_base) + { + // We currently do not support multiple contexts + fmt::throw_exception("sys_rsx_context_allocate was called twice" HERE); + } + + const auto area = vm::reserve_map(vm::rsx_context, 0, 0x10000000, 0x403); + const u32 context_base = area ? area->alloc(0x300000) : 0; + + if (!context_base) + { + return CELL_ENOMEM; + } + + *lpar_dma_control = context_base; + *lpar_driver_info = context_base + 0x100000; + *lpar_reports = context_base + 0x200000; auto &reports = vm::_ref(*lpar_reports); std::memset(&reports, 0, sizeof(RsxReports)); @@ -147,7 +180,7 @@ error_code sys_rsx_context_allocate(vm::ptr context_id, vm::ptr lpar_d driverInfo.systemModeFlags = system_mode; driverInfo.hardware_channel = 1; // * i think* this 1 for games, 0 for vsh - rsx_cfg->driverInfo = *lpar_driver_info; + rsx_cfg->driver_info = *lpar_driver_info; auto &dmaControl = vm::_ref(*lpar_dma_control); dmaControl.get = 0; @@ -175,9 +208,12 @@ error_code sys_rsx_context_allocate(vm::ptr context_id, vm::ptr lpar_d render->display_buffers_count = 0; render->current_display_buffer = 0; render->label_addr = *lpar_reports; - render->ctxt_addr = rsx_cfg->rsx_context_addr; + render->device_addr = rsx_cfg->device_addr; render->init(*lpar_dma_control); + rsx_cfg->context_base = context_base; + *context_id = 0x55555555; + return CELL_OK; } @@ -189,6 +225,15 @@ error_code sys_rsx_context_free(u32 context_id) { sys_rsx.todo("sys_rsx_context_free(context_id=0x%x)", context_id); + std::scoped_lock lock(s_rsxmem_mtx); + + auto rsx_cfg = g_fxo->get(); + + if (context_id != 0x55555555 || !rsx_cfg->context_base) + { + return CELL_EINVAL; + } + return CELL_OK; } @@ -205,7 +250,7 @@ error_code sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 f sys_rsx.warning("sys_rsx_context_iomap(context_id=0x%x, io=0x%x, ea=0x%x, size=0x%x, flags=0x%llx)", context_id, io, ea, size, flags); if (!size || io & 0xFFFFF || ea + u64{size} > rsx::constants::local_mem_base || ea & 0xFFFFF || size & 0xFFFFF || - rsx::get_current_renderer()->main_mem_size < io + u64{size}) + context_id != 0x55555555 || rsx::get_current_renderer()->main_mem_size < io + u64{size}) { return CELL_EINVAL; } @@ -244,7 +289,8 @@ error_code sys_rsx_context_iounmap(u32 context_id, u32 io, u32 size) { sys_rsx.warning("sys_rsx_context_iounmap(context_id=0x%x, io=0x%x, size=0x%x)", context_id, io, size); - if (!size || size & 0xFFFFF || io & 0xFFFFF || rsx::get_current_renderer()->main_mem_size < io + u64{size}) + if (!size || size & 0xFFFFF || io & 0xFFFFF || context_id != 0x55555555 || + rsx::get_current_renderer()->main_mem_size < io + u64{size}) { return CELL_EINVAL; } @@ -273,7 +319,7 @@ error_code sys_rsx_context_iounmap(u32 context_id, u32 io, u32 size) * @param a5 (IN): * @param a6 (IN): */ -error_code sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6) +error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6) { // Flip/queue/reset flip/flip event/user command/vblank as trace to help with log spam if (package_id == 0x102 || package_id == 0x103 || package_id == 0x10a || package_id == 0xFEC || package_id == 0xFED || package_id == 0xFEF) @@ -287,12 +333,12 @@ error_code sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 auto rsx_cfg = g_fxo->get(); - if (!rsx_cfg->state) + if (!rsx_cfg->context_base || context_id != 0x55555555) { return CELL_EINVAL; } - auto &driverInfo = vm::_ref(rsx_cfg->driverInfo); + auto &driverInfo = vm::_ref(rsx_cfg->driver_info); switch (package_id) { case 0x001: // FIFO @@ -502,7 +548,7 @@ error_code sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 case 0xFED: // hack: vblank command // todo: this is wrong and should be 'second' vblank handler and freq, but since currently everything is reported as being 59.94, this should be fine - vm::_ref(render->ctxt_addr + 0x30) = 1; + vm::_ref(render->device_addr + 0x30) = 1; driverInfo.head[a3].vBlankCount++; driverInfo.head[a3].lastSecondVTime = rsxTimeStamp(); sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 1), 0); @@ -530,7 +576,7 @@ error_code sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 /* * lv2 SysCall 675 (0x2A3): sys_rsx_device_map * @param a1 (OUT): rsx device map address : 0x40000000, 0x50000000.. 0xB0000000 - * @param a2 (OUT): Unused? + * @param a2 (OUT): Unused * @param dev_id (IN): An immediate value and always 8. (cellGcmInitPerfMon uses 11, 10, 9, 7, 12 successively). */ error_code sys_rsx_device_map(vm::ptr dev_addr, vm::ptr a2, u32 dev_id) @@ -542,25 +588,27 @@ error_code sys_rsx_device_map(vm::ptr dev_addr, vm::ptr a2, u32 dev_id fmt::throw_exception("sys_rsx_device_map: Invalid dev_id %d", dev_id); } - // a2 seems to not be referenced in cellGcmSys, tests show this arg is ignored - //*a2 = 0; - auto rsx_cfg = g_fxo->get(); - // TODO - if (!rsx_cfg->state.compare_and_swap_test(0, 1)) - { - return CELL_EINVAL; // sys_rsx_device_map called twice - } + static shared_mutex device_map_mtx; + std::scoped_lock lock(device_map_mtx); - if (const auto area = vm::find_map(0x10000000, 0x10000000, 0x403)) + if (!rsx_cfg->device_addr) { - vm::falloc(area->addr, 0x400000); - rsx_cfg->rsx_context_addr = *dev_addr = area->addr; + const auto area = vm::reserve_map(vm::rsx_context, 0, 0x10000000, 0x403); + const u32 addr = area ? area->alloc(0x100000) : 0; + + if (!addr) + { + return CELL_ENOMEM; + } + + rsx_cfg->device_addr = *dev_addr = addr; return CELL_OK; } - return CELL_ENOMEM; + *dev_addr = rsx_cfg->device_addr; + return CELL_OK; } /* diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.h b/rpcs3/Emu/Cell/lv2/sys_rsx.h index 055ed2c6b2..dd844c804c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.h +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.h @@ -1,6 +1,4 @@ -#pragma once - -#include "Emu/Memory/vm_ptr.h" +#pragma once #include "Emu/Memory/vm_ptr.h" @@ -105,10 +103,10 @@ struct RsxDisplayInfo struct lv2_rsx_config { - atomic_t state = 0; - u32 rsx_event_port = 0; - u32 driverInfo = 0; - u32 rsx_context_addr = 0; + u32 rsx_event_port{}; + u32 context_base{}; + u32 device_addr{}; + u32 driver_info{}; }; // SysCalls @@ -120,7 +118,7 @@ error_code sys_rsx_context_allocate(vm::ptr context_id, vm::ptr lpar_d error_code sys_rsx_context_free(u32 context_id); error_code sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 flags); error_code sys_rsx_context_iounmap(u32 context_id, u32 io, u32 size); -error_code sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6); +error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6); error_code sys_rsx_device_map(vm::ptr dev_addr, vm::ptr a2, u32 dev_id); error_code sys_rsx_device_unmap(u32 dev_id); error_code sys_rsx_attribute(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5); diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 6ceb0f82ef..8c3c714fa8 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -1087,6 +1087,7 @@ namespace vm std::make_shared(0x00010000, 0x1FFF0000, 0x200), // main std::make_shared(0x20000000, 0x10000000, 0x201), // user 64k pages nullptr, // user 1m pages + nullptr, // rsx context std::make_shared(0xC0000000, 0x10000000), // video std::make_shared(0xD0000000, 0x10000000, 0x111), // stack std::make_shared(0xE0000000, 0x20000000), // SPU reserved diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index c200964f63..cf69d302a4 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -22,6 +22,7 @@ namespace vm main, user64k, user1m, + rsx_context, video, stack, spu, diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 961e0f7007..99d41a5d9a 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -91,10 +91,10 @@ namespace rsx return get_current_renderer()->label_addr + offset; case CELL_GCM_CONTEXT_DMA_DEVICE_RW: - return get_current_renderer()->ctxt_addr + offset; + return get_current_renderer()->device_addr + offset; case CELL_GCM_CONTEXT_DMA_DEVICE_R: - return get_current_renderer()->ctxt_addr + offset; + return get_current_renderer()->device_addr + offset; default: { diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index d0f549cda7..505adcb286 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -564,7 +564,7 @@ namespace rsx RsxDisplayInfo display_buffers[8]; u32 display_buffers_count{0}; u32 current_display_buffer{0}; - u32 ctxt_addr; + u32 device_addr; u32 label_addr; u32 main_mem_size{0}; diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index c412b4713e..c4d5267573 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -74,7 +74,7 @@ namespace rsx const auto& sema = vm::_ref>(addr); // TODO: Remove vblank semaphore hack - if (sema == arg || addr == rsx->ctxt_addr + 0x30) return; + if (sema == arg || addr == rsx->device_addr + 0x30) return; rsx->flush_fifo();