rsx: rewrite io mappings

Along with some with fixes to cellGcmSys HLE.
This commit is contained in:
Eladash 2020-01-16 22:40:47 +02:00 committed by Ani
parent f47333997f
commit bdab26ec09
9 changed files with 233 additions and 186 deletions

View file

@ -49,23 +49,6 @@ const u32 tiled_pitches[] = {
0x00010000
};
struct gcm_config
{
u32 zculls_addr;
vm::ptr<CellGcmDisplayInfo> gcm_buffers = vm::null;
u32 tiles_addr;
u32 ctxt_addr;
CellGcmConfig current_config;
CellGcmContextData current_context;
gcmInfo gcm_info;
};
u64 system_mode = 0;
u32 local_size = 0;
u32 local_addr = 0;
atomic_t<u32> reserved_size = 0;
// Auxiliary functions
/*
@ -93,22 +76,31 @@ u32 gcmGetLocalMemorySize(u32 sdk_version)
return 0x0E000000; // 224MB
}
CellGcmOffsetTable offsetTable;
atomic_t<u16> IoMapTable[0xC00]{};
error_code gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict);
u32 gcmIoOffsetToAddress(u32 ioOffset)
{
const u32 upper12Bits = g_fxo->get<gcm_config>()->offsetTable.eaAddress[ioOffset >> 20];
if (static_cast<s16>(upper12Bits) < 0)
{
return 0;
}
return (upper12Bits << 20) | (ioOffset & 0xFFFFF);
}
void InitOffsetTable()
{
offsetTable.ioAddress.set(vm::alloc(3072 * sizeof(u16), vm::main));
offsetTable.eaAddress.set(vm::alloc(512 * sizeof(u16), vm::main));
const auto cfg = g_fxo->get<gcm_config>();
memset(offsetTable.ioAddress.get_ptr(), 0xFF, 3072 * sizeof(u16));
memset(offsetTable.eaAddress.get_ptr(), 0xFF, 512 * sizeof(u16));
memset(IoMapTable, 0, 3072 * sizeof(u16));
cfg->offsetTable.ioAddress.set(vm::alloc(3072 * sizeof(u16), vm::main));
cfg->offsetTable.eaAddress.set(vm::alloc(512 * sizeof(u16), vm::main));
memset(&RSXIOMem, 0xFF, sizeof(RSXIOMem));
reserved_size = 0;
std::memset(cfg->offsetTable.ioAddress.get_ptr(), 0xFF, 3072 * sizeof(u16));
std::memset(cfg->offsetTable.eaAddress.get_ptr(), 0xFF, 512 * sizeof(u16));
cfg->reserved_size = 0;
}
//----------------------------------------------------------------------------
@ -132,7 +124,7 @@ vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 lo
cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong main index (%d)", index);
}
return vm::ptr<CellGcmReportData>::make(RSXIOMem.RealAddr(0x0e000000 + index * 0x10));
return vm::cast(gcmIoOffsetToAddress(0x0e000000 + index * 0x10));
}
// Anything else is Local
@ -142,7 +134,7 @@ vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 lo
cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong local index (%d)", index);
}
return vm::ptr<CellGcmReportData>::make(g_fxo->get<gcm_config>()->gcm_info.label_addr + ::offset32(&RsxReports::report) + index * 0x10);
return vm::cast(g_fxo->get<gcm_config>()->gcm_info.label_addr + ::offset32(&RsxReports::report) + index * 0x10);
}
u64 cellGcmGetTimeStamp(u32 index)
@ -168,7 +160,7 @@ u32 cellGcmGetNotifyDataAddress(u32 index)
cellGcmSys.warning("cellGcmGetNotifyDataAddress(index=%d)", index);
// If entry not in use, return NULL
u16 entry = offsetTable.eaAddress[241];
u16 entry = g_fxo->get<gcm_config>()->offsetTable.eaAddress[241];
if (entry == 0xFFFF) {
return 0;
}
@ -225,24 +217,8 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location)
{
cellGcmSys.warning("cellGcmGetTimeStampLocation(index=%d, location=%d)", index, location);
if (location == CELL_GCM_LOCATION_LOCAL) {
if (index >= 2048) {
cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong local index (%d)", index);
return 0;
}
return vm::read64(g_fxo->get<gcm_config>()->gcm_info.label_addr + ::offset32(&RsxReports::report) + index * 0x10);
}
if (location == CELL_GCM_LOCATION_MAIN) {
if (index >= 1024 * 1024) {
cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong main index (%d)", index);
return 0;
}
return vm::read64(RSXIOMem.RealAddr(index * 0x10));
}
cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong location (%d)", location);
return 0;
// NOTE: No error checkings
return cellGcmGetReportDataAddressLocation(index, location)->timer;
}
//----------------------------------------------------------------------------
@ -365,25 +341,26 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> contex
cellGcmSys.warning("_cellGcmInitBody(context=**0x%x, cmdSize=0x%x, ioSize=0x%x, ioAddress=0x%x)", context, cmdSize, ioSize, ioAddress);
const auto gcm_cfg = g_fxo->get<gcm_config>();
std::lock_guard lock(gcm_cfg->gcmio_mutex);
gcm_cfg->current_config.ioAddress = 0;
gcm_cfg->current_config.localAddress = 0;
local_size = 0;
local_addr = 0;
gcm_cfg->local_size = 0;
gcm_cfg->local_addr = 0;
if (!local_size && !local_addr)
//if (!gcm_cfg->local_size && !gcm_cfg->local_addr)
{
local_size = 0xf900000; // TODO: Get sdk_version in _cellGcmFunc15 and pass it to gcmGetLocalMemorySize
local_addr = rsx::constants::local_mem_base;
vm::falloc(local_addr, local_size, vm::video);
gcm_cfg->local_size = 0xf900000; // TODO: Get sdk_version in _cellGcmFunc15 and pass it to gcmGetLocalMemorySize
gcm_cfg->local_addr = rsx::constants::local_mem_base;
vm::falloc(gcm_cfg->local_addr, gcm_cfg->local_size, vm::video);
}
cellGcmSys.warning("*** local memory(addr=0x%x, size=0x%x)", local_addr, local_size);
cellGcmSys.warning("*** local memory(addr=0x%x, size=0x%x)", gcm_cfg->local_addr, gcm_cfg->local_size);
InitOffsetTable();
const auto render = rsx::get_current_renderer();
if (system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB)
if (gcm_cfg->system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB)
{
cellGcmSys.warning("cellGcmInit(): 512MB io address space used");
render->main_mem_size = 0x20000000;
@ -401,8 +378,8 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> contex
gcm_cfg->current_config.ioSize = ioSize;
gcm_cfg->current_config.ioAddress = ioAddress;
gcm_cfg->current_config.localSize = local_size;
gcm_cfg->current_config.localAddress = local_addr;
gcm_cfg->current_config.localSize = gcm_cfg->local_size;
gcm_cfg->current_config.localAddress = gcm_cfg->local_addr;
gcm_cfg->current_config.memoryFrequency = 650000000;
gcm_cfg->current_config.coreFrequency = 500000000;
@ -446,7 +423,7 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> contex
render->isHLE = true;
render->label_addr = gcm_cfg->gcm_info.label_addr;
render->device_addr = gcm_cfg->gcm_info.context_addr;
render->local_mem_size = local_size;
render->local_mem_size = gcm_cfg->local_size;
render->init(gcm_cfg->gcm_info.control_addr - 0x40);
return CELL_OK;
@ -855,7 +832,7 @@ error_code cellGcmInitSystemMode(u64 mode)
{
cellGcmSys.trace("cellGcmInitSystemMode(mode=0x%x)", mode);
system_mode = mode;
g_fxo->get<gcm_config>()->system_mode = mode;
return CELL_OK;
}
@ -930,7 +907,7 @@ error_code cellGcmAddressToOffset(u32 address, vm::ptr<u32> offset)
// Address in main memory else check
else
{
const u32 upper12Bits = offsetTable.ioAddress[address >> 20];
const u32 upper12Bits = g_fxo->get<gcm_config>()->offsetTable.ioAddress[address >> 20];
// If the address is mapped in IO
if (upper12Bits != 0xFFFF)
@ -951,29 +928,31 @@ u32 cellGcmGetMaxIoMapSize()
{
cellGcmSys.trace("cellGcmGetMaxIoMapSize()");
return rsx::get_current_renderer()->main_mem_size - reserved_size;
return rsx::get_current_renderer()->main_mem_size - g_fxo->get<gcm_config>()->reserved_size;
}
void cellGcmGetOffsetTable(vm::ptr<CellGcmOffsetTable> table)
{
cellGcmSys.trace("cellGcmGetOffsetTable(table=*0x%x)", table);
table->ioAddress = offsetTable.ioAddress;
table->eaAddress = offsetTable.eaAddress;
const auto cfg = g_fxo->get<gcm_config>();
table->ioAddress = cfg->offsetTable.ioAddress;
table->eaAddress = cfg->offsetTable.eaAddress;
}
error_code cellGcmIoOffsetToAddress(u32 ioOffset, vm::ptr<u32> address)
{
cellGcmSys.trace("cellGcmIoOffsetToAddress(ioOffset=0x%x, address=*0x%x)", ioOffset, address);
const u32 upper12Bits = offsetTable.eaAddress[ioOffset >> 20];
const u32 addr = gcmIoOffsetToAddress(ioOffset);
if (static_cast<s16>(upper12Bits) < 0)
if (!addr)
{
return CELL_GCM_ERROR_FAILURE;
}
*address = (upper12Bits << 20) | (ioOffset & 0xFFFFF);
*address = addr;
return CELL_OK;
}
@ -990,16 +969,18 @@ error_code gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict)
return error;
}
// Assume lock is acquired
const auto cfg = g_fxo->get<gcm_config>();
ea >>= 20, io >>= 20, size >>= 20;
// Fill the offset table
for (u32 i = 0; i < size; i++)
{
offsetTable.ioAddress[ea + i] = io + i;
offsetTable.eaAddress[io + i] = ea + i;
cfg->offsetTable.ioAddress[ea + i] = io + i;
cfg->offsetTable.eaAddress[io + i] = ea + i;
}
IoMapTable[ea] = size;
cfg->IoMapTable[ea] = size;
return CELL_OK;
}
@ -1007,6 +988,9 @@ error_code cellGcmMapEaIoAddress(u32 ea, u32 io, u32 size)
{
cellGcmSys.warning("cellGcmMapEaIoAddress(ea=0x%x, io=0x%x, size=0x%x)", ea, io, size);
const auto cfg = g_fxo->get<gcm_config>();
std::lock_guard lock(cfg->gcmio_mutex);
return gcmMapEaIoAddress(ea, io, size, false);
}
@ -1016,6 +1000,9 @@ error_code cellGcmMapEaIoAddressWithFlags(u32 ea, u32 io, u32 size, u32 flags)
verify(HERE), flags == 2 /*CELL_GCM_IOMAP_FLAG_STRICT_ORDERING*/;
const auto cfg = g_fxo->get<gcm_config>();
std::lock_guard lock(cfg->gcmio_mutex);
return gcmMapEaIoAddress(ea, io, size, true);
}
@ -1023,17 +1010,17 @@ error_code cellGcmMapLocalMemory(vm::ptr<u32> address, vm::ptr<u32> size)
{
cellGcmSys.warning("cellGcmMapLocalMemory(address=*0x%x, size=*0x%x)", address, size);
if (!local_addr && !local_size && vm::falloc(local_addr = rsx::constants::local_mem_base, local_size = 0xf900000 /* TODO */, vm::video))
const auto cfg = g_fxo->get<gcm_config>();
std::lock_guard lock(cfg->gcmio_mutex);
if (!cfg->local_addr && !cfg->local_size && vm::falloc(cfg->local_addr = rsx::constants::local_mem_base, cfg->local_size = 0xf900000 /* TODO */, vm::video))
{
*address = local_addr;
*size = local_size;
}
else
{
return CELL_GCM_ERROR_FAILURE;
*address = cfg->local_addr;
*size = cfg->local_size;
return CELL_OK;
}
return CELL_OK;
return CELL_GCM_ERROR_FAILURE;
}
error_code cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr<u32> offset)
@ -1042,10 +1029,13 @@ error_code cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr<u32> offset)
if (!size || (ea & 0xFFFFF) || (size & 0xFFFFF)) return CELL_GCM_ERROR_FAILURE;
const auto cfg = g_fxo->get<gcm_config>();
std::lock_guard lock(cfg->gcmio_mutex);
// Use the offset table to find the next free io address
for (u32 io = 0, end = (rsx::get_current_renderer()->main_mem_size - reserved_size) >> 20, unmap_count = 1; io < end; unmap_count++)
for (u32 io = 0, end = (rsx::get_current_renderer()->main_mem_size - cfg->reserved_size) >> 20, unmap_count = 1; io < end; unmap_count++)
{
if (static_cast<s16>(offsetTable.eaAddress[io + unmap_count - 1]) < 0)
if (static_cast<s16>(cfg->offsetTable.eaAddress[io + unmap_count - 1]) < 0)
{
if (unmap_count >= (size >> 20))
{
@ -1079,12 +1069,15 @@ error_code cellGcmReserveIoMapSize(u32 size)
return CELL_GCM_ERROR_INVALID_ALIGNMENT;
}
const auto cfg = g_fxo->get<gcm_config>();
std::lock_guard lock(cfg->gcmio_mutex);
if (size > cellGcmGetMaxIoMapSize())
{
return CELL_GCM_ERROR_INVALID_VALUE;
}
reserved_size += size;
cfg->reserved_size += size;
return CELL_OK;
}
@ -1092,48 +1085,60 @@ error_code cellGcmUnmapEaIoAddress(u32 ea)
{
cellGcmSys.warning("cellGcmUnmapEaIoAddress(ea=0x%x)", ea);
if (const u32 size = IoMapTable[ea >>= 20].exchange(0))
const auto cfg = g_fxo->get<gcm_config>();
std::lock_guard lock(cfg->gcmio_mutex);
if (const u32 size = cfg->IoMapTable[ea >> 20])
{
const u32 io = offsetTable.ioAddress[ea];
u32 io = cfg->offsetTable.ioAddress[ea];
if (auto error = sys_rsx_context_iounmap(0x55555555, io, size))
{
return error;
}
ea >>= 20, io >>= 20;
const auto render = rsx::get_current_renderer();
for (u32 i = 0; i < size; i++)
{
RSXIOMem.io[ea + i].raw() = offsetTable.ioAddress[ea + i] = 0xFFFF;
RSXIOMem.ea[io + i].raw() = offsetTable.eaAddress[io + i] = 0xFFFF;
cfg->offsetTable.ioAddress[ea + i] = 0xFFFF;
cfg->offsetTable.eaAddress[io + i] = 0xFFFF;
}
std::atomic_thread_fence(std::memory_order_seq_cst);
}
else
{
return CELL_GCM_ERROR_FAILURE;
cfg->IoMapTable[ea] = 0;
return CELL_OK;
}
return CELL_OK;
return CELL_GCM_ERROR_FAILURE;
}
error_code cellGcmUnmapIoAddress(u32 io)
{
cellGcmSys.warning("cellGcmUnmapIoAddress(io=0x%x)", io);
if (u32 size = IoMapTable[RSXIOMem.ea[io >>= 20]].exchange(0))
{
const u32 ea = offsetTable.eaAddress[io];
const auto cfg = g_fxo->get<gcm_config>();
std::lock_guard lock(cfg->gcmio_mutex);
for (u32 i = 0; i < size; i++)
if (u32 ea = cfg->offsetTable.eaAddress[io >>= 20], size = cfg->IoMapTable[ea]; size)
{
if (auto error = sys_rsx_context_iounmap(0x55555555, io, size))
{
RSXIOMem.io[ea + i].raw() = offsetTable.ioAddress[ea + i] = 0xFFFF;
RSXIOMem.ea[io + i].raw() = offsetTable.eaAddress[io + i] = 0xFFFF;
return error;
}
std::atomic_thread_fence(std::memory_order_seq_cst);
}
else
{
return CELL_GCM_ERROR_FAILURE;
const auto render = rsx::get_current_renderer();
for (u32 i = 0; i < size; i++)
{
cfg->offsetTable.ioAddress[ea + i] = 0xFFFF;
cfg->offsetTable.eaAddress[io + i] = 0xFFFF;
}
return CELL_OK;
}
return CELL_OK;
return CELL_GCM_ERROR_FAILURE;
}
error_code cellGcmUnreserveIoMapSize(u32 size)
@ -1145,12 +1150,15 @@ error_code cellGcmUnreserveIoMapSize(u32 size)
return CELL_GCM_ERROR_INVALID_ALIGNMENT;
}
if (size > reserved_size)
const auto cfg = g_fxo->get<gcm_config>();
std::lock_guard lock(cfg->gcmio_mutex);
if (size > cfg->reserved_size)
{
return CELL_GCM_ERROR_INVALID_VALUE;
}
reserved_size -= size;
cfg->reserved_size -= size;
return CELL_OK;
}
@ -1375,7 +1383,7 @@ static std::pair<u32, u32> getNextCommandBufferBeginEnd(u32 current)
static u32 getOffsetFromAddress(u32 address)
{
const u32 upper = offsetTable.ioAddress[address >> 20]; // 12 bits
const u32 upper = g_fxo->get<gcm_config>()->offsetTable.ioAddress[address >> 20]; // 12 bits
verify(HERE), (upper != 0xFFFF);
return (upper << 20) | (address & 0xFFFFF);
}