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.
This commit is contained in:
eladash 2018-10-31 04:40:04 +02:00 committed by kd-11
parent 90aaaceba0
commit 730e9cde84
8 changed files with 96 additions and 50 deletions

View File

@ -389,11 +389,9 @@ s32 _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> context, u32
gcm_cfg->current_config.coreFrequency = 500000000; gcm_cfg->current_config.coreFrequency = 500000000;
// Create contexts // Create contexts
auto ctx_area = vm::find_map(0x10000000, 0x10000000, 0x403); const auto area = vm::reserve_map(vm::rsx_context, 0, 0x10000000, 0x403);
u32 rsx_ctxaddr = ctx_area ? ctx_area->addr : 0; const u32 rsx_ctxaddr = area ? area->alloc(0x400000) : 0;
verify(HERE), rsx_ctxaddr != 0;
if (!rsx_ctxaddr || vm::falloc(rsx_ctxaddr, 0x400000) != rsx_ctxaddr)
fmt::throw_exception("Failed to alloc rsx context.");
g_defaultCommandBufferBegin = ioAddress; g_defaultCommandBufferBegin = ioAddress;
g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024); g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024);
@ -429,7 +427,7 @@ s32 _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> context, u32
render->intr_thread->state -= cpu_flag::stop; render->intr_thread->state -= cpu_flag::stop;
render->isHLE = true; render->isHLE = true;
render->label_addr = gcm_cfg->gcm_info.label_addr; 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); render->init(gcm_cfg->gcm_info.control_addr - 0x40);
return CELL_OK; return CELL_OK;

View File

@ -68,10 +68,14 @@ error_code sys_rsx_memory_allocate(vm::ptr<u32> mem_handle, vm::ptr<u64> 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); 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; if (u32 addr = vm::falloc(rsx::constants::local_mem_base, size, vm::video))
*mem_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<u32> mem_handle, vm::ptr<u64> mem_add
*/ */
error_code sys_rsx_memory_free(u32 mem_handle) 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<lv2_rsx_config>()->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; return CELL_OK;
} }
@ -99,18 +118,32 @@ error_code sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> 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)", 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); context_id, lpar_dma_control, lpar_driver_info, lpar_reports, mem_ctx, system_mode);
auto rsx_cfg = g_fxo->get<lv2_rsx_config>(); if (!vm::check_addr(rsx::constants::local_mem_base))
if (!rsx_cfg->state)
{ {
return CELL_EINVAL; return CELL_EINVAL;
} }
*context_id = 0x55555555; auto rsx_cfg = g_fxo->get<lv2_rsx_config>();
*lpar_dma_control = rsx_cfg->rsx_context_addr + 0x100000; std::lock_guard lock(s_rsxmem_mtx);
*lpar_driver_info = rsx_cfg->rsx_context_addr + 0x200000;
*lpar_reports = rsx_cfg->rsx_context_addr + 0x300000; 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<RsxReports>(*lpar_reports); auto &reports = vm::_ref<RsxReports>(*lpar_reports);
std::memset(&reports, 0, sizeof(RsxReports)); std::memset(&reports, 0, sizeof(RsxReports));
@ -147,7 +180,7 @@ error_code sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> lpar_d
driverInfo.systemModeFlags = system_mode; driverInfo.systemModeFlags = system_mode;
driverInfo.hardware_channel = 1; // * i think* this 1 for games, 0 for vsh 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<RsxDmaControl>(*lpar_dma_control); auto &dmaControl = vm::_ref<RsxDmaControl>(*lpar_dma_control);
dmaControl.get = 0; dmaControl.get = 0;
@ -175,9 +208,12 @@ error_code sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> lpar_d
render->display_buffers_count = 0; render->display_buffers_count = 0;
render->current_display_buffer = 0; render->current_display_buffer = 0;
render->label_addr = *lpar_reports; 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); render->init(*lpar_dma_control);
rsx_cfg->context_base = context_base;
*context_id = 0x55555555;
return CELL_OK; 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); 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<lv2_rsx_config>();
if (context_id != 0x55555555 || !rsx_cfg->context_base)
{
return CELL_EINVAL;
}
return CELL_OK; 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); 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 || 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; 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); 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; return CELL_EINVAL;
} }
@ -273,7 +319,7 @@ error_code sys_rsx_context_iounmap(u32 context_id, u32 io, u32 size)
* @param a5 (IN): * @param a5 (IN):
* @param a6 (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 // 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) 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<lv2_rsx_config>(); auto rsx_cfg = g_fxo->get<lv2_rsx_config>();
if (!rsx_cfg->state) if (!rsx_cfg->context_base || context_id != 0x55555555)
{ {
return CELL_EINVAL; return CELL_EINVAL;
} }
auto &driverInfo = vm::_ref<RsxDriverInfo>(rsx_cfg->driverInfo); auto &driverInfo = vm::_ref<RsxDriverInfo>(rsx_cfg->driver_info);
switch (package_id) switch (package_id)
{ {
case 0x001: // FIFO 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 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 // 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<u32>(render->ctxt_addr + 0x30) = 1; vm::_ref<u32>(render->device_addr + 0x30) = 1;
driverInfo.head[a3].vBlankCount++; driverInfo.head[a3].vBlankCount++;
driverInfo.head[a3].lastSecondVTime = rsxTimeStamp(); driverInfo.head[a3].lastSecondVTime = rsxTimeStamp();
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 1), 0); 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 * lv2 SysCall 675 (0x2A3): sys_rsx_device_map
* @param a1 (OUT): rsx device map address : 0x40000000, 0x50000000.. 0xB0000000 * @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). * @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<u64> dev_addr, vm::ptr<u64> a2, u32 dev_id) error_code sys_rsx_device_map(vm::ptr<u64> dev_addr, vm::ptr<u64> a2, u32 dev_id)
@ -542,25 +588,27 @@ error_code sys_rsx_device_map(vm::ptr<u64> dev_addr, vm::ptr<u64> a2, u32 dev_id
fmt::throw_exception("sys_rsx_device_map: Invalid dev_id %d", 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<lv2_rsx_config>(); auto rsx_cfg = g_fxo->get<lv2_rsx_config>();
// TODO static shared_mutex device_map_mtx;
if (!rsx_cfg->state.compare_and_swap_test(0, 1)) std::scoped_lock lock(device_map_mtx);
{
return CELL_EINVAL; // sys_rsx_device_map called twice
}
if (const auto area = vm::find_map(0x10000000, 0x10000000, 0x403)) if (!rsx_cfg->device_addr)
{ {
vm::falloc(area->addr, 0x400000); const auto area = vm::reserve_map(vm::rsx_context, 0, 0x10000000, 0x403);
rsx_cfg->rsx_context_addr = *dev_addr = area->addr; 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_OK;
} }
return CELL_ENOMEM; *dev_addr = rsx_cfg->device_addr;
return CELL_OK;
} }
/* /*

View File

@ -1,6 +1,4 @@
#pragma once #pragma once
#include "Emu/Memory/vm_ptr.h"
#include "Emu/Memory/vm_ptr.h" #include "Emu/Memory/vm_ptr.h"
@ -105,10 +103,10 @@ struct RsxDisplayInfo
struct lv2_rsx_config struct lv2_rsx_config
{ {
atomic_t<u32> state = 0; u32 rsx_event_port{};
u32 rsx_event_port = 0; u32 context_base{};
u32 driverInfo = 0; u32 device_addr{};
u32 rsx_context_addr = 0; u32 driver_info{};
}; };
// SysCalls // SysCalls
@ -120,7 +118,7 @@ error_code sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> lpar_d
error_code sys_rsx_context_free(u32 context_id); 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_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_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<u64> dev_addr, vm::ptr<u64> a2, u32 dev_id); error_code sys_rsx_device_map(vm::ptr<u64> dev_addr, vm::ptr<u64> a2, u32 dev_id);
error_code sys_rsx_device_unmap(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); error_code sys_rsx_attribute(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5);

View File

@ -1087,6 +1087,7 @@ namespace vm
std::make_shared<block_t>(0x00010000, 0x1FFF0000, 0x200), // main std::make_shared<block_t>(0x00010000, 0x1FFF0000, 0x200), // main
std::make_shared<block_t>(0x20000000, 0x10000000, 0x201), // user 64k pages std::make_shared<block_t>(0x20000000, 0x10000000, 0x201), // user 64k pages
nullptr, // user 1m pages nullptr, // user 1m pages
nullptr, // rsx context
std::make_shared<block_t>(0xC0000000, 0x10000000), // video std::make_shared<block_t>(0xC0000000, 0x10000000), // video
std::make_shared<block_t>(0xD0000000, 0x10000000, 0x111), // stack std::make_shared<block_t>(0xD0000000, 0x10000000, 0x111), // stack
std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU reserved std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU reserved

View File

@ -22,6 +22,7 @@ namespace vm
main, main,
user64k, user64k,
user1m, user1m,
rsx_context,
video, video,
stack, stack,
spu, spu,

View File

@ -91,10 +91,10 @@ namespace rsx
return get_current_renderer()->label_addr + offset; return get_current_renderer()->label_addr + offset;
case CELL_GCM_CONTEXT_DMA_DEVICE_RW: 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: case CELL_GCM_CONTEXT_DMA_DEVICE_R:
return get_current_renderer()->ctxt_addr + offset; return get_current_renderer()->device_addr + offset;
default: default:
{ {

View File

@ -564,7 +564,7 @@ namespace rsx
RsxDisplayInfo display_buffers[8]; RsxDisplayInfo display_buffers[8];
u32 display_buffers_count{0}; u32 display_buffers_count{0};
u32 current_display_buffer{0}; u32 current_display_buffer{0};
u32 ctxt_addr; u32 device_addr;
u32 label_addr; u32 label_addr;
u32 main_mem_size{0}; u32 main_mem_size{0};

View File

@ -74,7 +74,7 @@ namespace rsx
const auto& sema = vm::_ref<atomic_be_t<u32>>(addr); const auto& sema = vm::_ref<atomic_be_t<u32>>(addr);
// TODO: Remove vblank semaphore hack // 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(); rsx->flush_fifo();