2008-01-15 20:27:44 +00:00
|
|
|
#include "Iop_Sysmem.h"
|
2025-03-11 12:48:26 -04:00
|
|
|
#include "Log.h"
|
2012-09-18 06:33:33 +00:00
|
|
|
#include "Iop_SifMan.h"
|
2008-01-15 20:27:44 +00:00
|
|
|
|
|
|
|
using namespace Iop;
|
|
|
|
|
2008-01-21 04:09:08 +00:00
|
|
|
#define LOG_NAME ("iop_sysmem")
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
#define FUNCTION_ALLOCATEMEMORY "AllocateMemory"
|
|
|
|
#define FUNCTION_FREEMEMORY "FreeMemory"
|
|
|
|
#define FUNCTION_PRINTF "printf"
|
|
|
|
#define FUNCTION_QUERYMEMSIZE "QueryMemSize"
|
|
|
|
#define FUNCTION_QUERYMAXFREEMEMSIZE "QueryMaxFreeMemSize"
|
2019-01-15 21:31:17 +00:00
|
|
|
#define FUNCTION_QUERYTOTALFREEMEMSIZE "QueryTotalFreeMemSize"
|
2008-12-11 03:53:33 +00:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
#define MIN_BLOCK_SIZE 0x100
|
2008-12-08 03:43:30 +00:00
|
|
|
|
2016-02-27 18:34:51 -05:00
|
|
|
CSysmem::CSysmem(uint8* ram, uint32 memoryBegin, uint32 memoryEnd, BlockListType& blocks, CStdio& stdio, CIoman& ioman, CSifMan& sifMan)
|
2018-04-30 21:01:23 +01:00
|
|
|
: m_iopRam(ram)
|
|
|
|
, m_stdio(stdio)
|
|
|
|
, m_ioman(ioman)
|
|
|
|
, m_blocks(blocks)
|
2023-05-02 08:56:25 -04:00
|
|
|
, m_memoryBegin(memoryBegin)
|
|
|
|
, m_memorySize(memoryEnd - memoryBegin)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2012-09-16 00:28:14 +00:00
|
|
|
//Initialize block map
|
2009-02-03 19:17:16 +00:00
|
|
|
m_headBlockId = m_blocks.Allocate();
|
2016-02-14 21:39:28 -05:00
|
|
|
auto block = m_blocks[m_headBlockId];
|
2018-04-30 21:01:23 +01:00
|
|
|
block->address = m_memorySize;
|
|
|
|
block->size = 0;
|
|
|
|
block->nextBlockId = BlockListType::INVALID_ID;
|
2008-01-21 04:09:08 +00:00
|
|
|
|
2012-09-16 00:28:14 +00:00
|
|
|
//Register sif module
|
|
|
|
sifMan.RegisterModule(MODULE_ID, this);
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2012-09-16 00:28:14 +00:00
|
|
|
std::string CSysmem::GetId() const
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2012-09-16 00:28:14 +00:00
|
|
|
return "sysmem";
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2012-09-16 00:28:14 +00:00
|
|
|
std::string CSysmem::GetFunctionName(unsigned int functionId) const
|
2008-11-28 23:46:52 +00:00
|
|
|
{
|
2012-09-16 00:28:14 +00:00
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
return FUNCTION_ALLOCATEMEMORY;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
return FUNCTION_FREEMEMORY;
|
|
|
|
break;
|
2014-11-24 16:47:18 +00:00
|
|
|
case 6:
|
2014-11-30 18:47:28 -05:00
|
|
|
return FUNCTION_QUERYMEMSIZE;
|
2014-11-24 16:47:18 +00:00
|
|
|
break;
|
|
|
|
case 7:
|
2014-11-30 18:47:28 -05:00
|
|
|
return FUNCTION_QUERYMAXFREEMEMSIZE;
|
2014-11-24 16:47:18 +00:00
|
|
|
break;
|
2019-01-15 21:31:17 +00:00
|
|
|
case 8:
|
|
|
|
return FUNCTION_QUERYTOTALFREEMEMSIZE;
|
|
|
|
break;
|
2012-09-16 00:28:14 +00:00
|
|
|
case 14:
|
|
|
|
return FUNCTION_PRINTF;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
break;
|
|
|
|
}
|
2008-11-28 23:46:52 +00:00
|
|
|
}
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
void CSysmem::Invoke(CMIPS& context, unsigned int functionId)
|
|
|
|
{
|
2012-09-16 00:28:14 +00:00
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(AllocateMemory(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_State.nGPR[CMIPS::A1].nV[0],
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV[0],
|
|
|
|
context.m_State.nGPR[CMIPS::A2].nV[0]));
|
2012-09-16 00:28:14 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(FreeMemory(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_State.nGPR[CMIPS::A0].nV[0]));
|
2012-09-16 00:28:14 +00:00
|
|
|
break;
|
2014-11-24 16:47:18 +00:00
|
|
|
case 6:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = m_memorySize;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = QueryMaxFreeMemSize();
|
|
|
|
break;
|
2019-01-15 21:31:17 +00:00
|
|
|
case 8:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = QueryTotalFreeMemSize();
|
|
|
|
break;
|
2012-09-16 00:28:14 +00:00
|
|
|
case 14:
|
|
|
|
m_stdio.__printf(context);
|
|
|
|
break;
|
|
|
|
default:
|
2018-05-24 12:59:15 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "(%08X): Unknown function (%d) called.\r\n", context.m_State.nPC, functionId);
|
2012-09-16 00:28:14 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2008-12-08 03:43:30 +00:00
|
|
|
bool CSysmem::Invoke(uint32 method, uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram)
|
2008-01-21 04:09:08 +00:00
|
|
|
{
|
2021-03-08 09:15:00 -05:00
|
|
|
//On a real console, this is implemented by the FileIO module
|
|
|
|
//The functions that are available depend on the version of that module
|
2008-01-21 04:09:08 +00:00
|
|
|
switch(method)
|
|
|
|
{
|
|
|
|
case 0x01:
|
|
|
|
assert(retSize == 4);
|
|
|
|
ret[0] = SifAllocate(args[0]);
|
|
|
|
break;
|
2012-09-16 00:28:14 +00:00
|
|
|
case 0x02:
|
|
|
|
assert(argsSize == 4);
|
|
|
|
ret[0] = SifFreeMemory(args[0]);
|
|
|
|
break;
|
2014-11-08 21:53:56 -05:00
|
|
|
case 0x03:
|
|
|
|
assert(argsSize >= 4);
|
|
|
|
assert(retSize == 4);
|
|
|
|
ret[0] = SifLoadMemory(args[0], reinterpret_cast<const char*>(args) + 4);
|
|
|
|
break;
|
2008-01-21 04:09:08 +00:00
|
|
|
case 0x04:
|
|
|
|
assert(retSize == 4);
|
|
|
|
ret[0] = SifAllocateSystemMemory(args[0], args[1], args[2]);
|
|
|
|
break;
|
2021-03-08 09:15:00 -05:00
|
|
|
case 0x05:
|
2014-11-24 16:47:18 +00:00
|
|
|
ret[0] = m_memorySize;
|
|
|
|
break;
|
2021-03-08 09:15:00 -05:00
|
|
|
case 0x06:
|
2014-11-24 16:47:18 +00:00
|
|
|
ret[0] = QueryMaxFreeMemSize();
|
|
|
|
break;
|
2021-03-08 09:15:00 -05:00
|
|
|
case 0x07:
|
2019-01-15 21:31:17 +00:00
|
|
|
ret[0] = QueryTotalFreeMemSize();
|
|
|
|
break;
|
2008-01-21 04:09:08 +00:00
|
|
|
default:
|
2021-08-30 14:03:19 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "Unknown method invoked (0x%08X).\r\n", method);
|
2008-01-21 04:09:08 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-09-16 00:28:14 +00:00
|
|
|
return true;
|
2008-01-21 04:09:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-15 21:31:17 +00:00
|
|
|
uint32 CSysmem::QueryTotalFreeMemSize()
|
|
|
|
{
|
|
|
|
uint32 totalSize = 0;
|
|
|
|
uint32 begin = 0;
|
|
|
|
auto nextBlockId = &m_headBlockId;
|
|
|
|
auto nextBlock = m_blocks[*nextBlockId];
|
|
|
|
while(nextBlock != nullptr)
|
|
|
|
{
|
|
|
|
uint32 end = nextBlock->address;
|
|
|
|
totalSize += (end - begin);
|
|
|
|
begin = nextBlock->address + nextBlock->size;
|
|
|
|
nextBlockId = &nextBlock->nextBlockId;
|
|
|
|
nextBlock = m_blocks[*nextBlockId];
|
|
|
|
}
|
|
|
|
return totalSize;
|
|
|
|
}
|
|
|
|
|
2014-11-24 16:47:18 +00:00
|
|
|
uint32 CSysmem::QueryMaxFreeMemSize()
|
|
|
|
{
|
|
|
|
uint32 maxSize = 0;
|
|
|
|
uint32 begin = 0;
|
2016-02-28 15:50:04 -05:00
|
|
|
auto nextBlockId = &m_headBlockId;
|
2016-02-14 21:39:28 -05:00
|
|
|
auto nextBlock = m_blocks[*nextBlockId];
|
|
|
|
while(nextBlock != nullptr)
|
2014-11-24 16:47:18 +00:00
|
|
|
{
|
|
|
|
uint32 end = nextBlock->address;
|
2021-08-30 14:03:19 -04:00
|
|
|
assert(end >= begin);
|
2016-02-28 15:50:04 -05:00
|
|
|
if((end - begin) >= maxSize)
|
2014-11-24 16:47:18 +00:00
|
|
|
{
|
|
|
|
maxSize = end - begin;
|
|
|
|
}
|
|
|
|
begin = nextBlock->address + nextBlock->size;
|
2016-02-28 15:50:04 -05:00
|
|
|
nextBlockId = &nextBlock->nextBlockId;
|
2014-11-24 16:47:18 +00:00
|
|
|
nextBlock = m_blocks[*nextBlockId];
|
|
|
|
}
|
2021-08-30 14:03:19 -04:00
|
|
|
assert(maxSize <= m_memorySize);
|
2014-11-24 16:47:18 +00:00
|
|
|
return maxSize;
|
|
|
|
}
|
|
|
|
|
2011-02-26 22:42:59 +00:00
|
|
|
uint32 CSysmem::AllocateMemory(uint32 size, uint32 flags, uint32 wantedAddress)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "AllocateMemory(size = 0x%08X, flags = 0x%08X, wantedAddress = 0x%08X);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
size, flags, wantedAddress);
|
2014-07-10 23:34:01 -04:00
|
|
|
|
2011-02-26 22:42:59 +00:00
|
|
|
const uint32 blockSize = MIN_BLOCK_SIZE;
|
2016-07-09 18:00:43 -04:00
|
|
|
|
|
|
|
if(size > (0 - blockSize))
|
|
|
|
{
|
|
|
|
//Will be aligned up to 0, return failure
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-02-26 22:42:59 +00:00
|
|
|
size = ((size + (blockSize - 1)) / blockSize) * blockSize;
|
2009-02-03 19:17:16 +00:00
|
|
|
|
2011-02-26 22:42:59 +00:00
|
|
|
if(flags == 0 || flags == 1)
|
2009-02-03 19:17:16 +00:00
|
|
|
{
|
2011-02-26 22:42:59 +00:00
|
|
|
uint32 begin = 0;
|
|
|
|
uint32* nextBlockId = &m_headBlockId;
|
2016-02-14 21:39:28 -05:00
|
|
|
auto nextBlock = m_blocks[*nextBlockId];
|
|
|
|
while(nextBlock != nullptr)
|
2009-02-03 19:17:16 +00:00
|
|
|
{
|
2011-02-26 22:42:59 +00:00
|
|
|
uint32 end = nextBlock->address;
|
|
|
|
if((end - begin) >= size)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
begin = nextBlock->address + nextBlock->size;
|
2016-02-28 15:50:04 -05:00
|
|
|
nextBlockId = &nextBlock->nextBlockId;
|
2011-02-26 22:42:59 +00:00
|
|
|
nextBlock = m_blocks[*nextBlockId];
|
|
|
|
}
|
2018-04-30 21:01:23 +01:00
|
|
|
|
2016-02-14 21:39:28 -05:00
|
|
|
if(nextBlock != nullptr)
|
2011-02-26 22:42:59 +00:00
|
|
|
{
|
|
|
|
uint32 newBlockId = m_blocks.Allocate();
|
2016-02-28 00:56:49 -05:00
|
|
|
assert(newBlockId != BlockListType::INVALID_ID);
|
|
|
|
if(newBlockId == BlockListType::INVALID_ID)
|
2011-02-26 22:42:59 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2016-02-14 21:39:28 -05:00
|
|
|
auto newBlock = m_blocks[newBlockId];
|
2018-04-30 21:01:23 +01:00
|
|
|
newBlock->address = begin;
|
|
|
|
newBlock->size = size;
|
|
|
|
newBlock->nextBlockId = *nextBlockId;
|
2011-02-26 22:42:59 +00:00
|
|
|
*nextBlockId = newBlockId;
|
|
|
|
return begin + m_memoryBegin;
|
2009-02-03 19:17:16 +00:00
|
|
|
}
|
|
|
|
}
|
2011-02-26 22:42:59 +00:00
|
|
|
else if(flags == 2)
|
2009-02-03 19:17:16 +00:00
|
|
|
{
|
2011-02-26 22:42:59 +00:00
|
|
|
assert(wantedAddress != 0);
|
|
|
|
wantedAddress -= m_memoryBegin;
|
|
|
|
|
|
|
|
uint32 begin = 0;
|
|
|
|
uint32* nextBlockId = &m_headBlockId;
|
2016-02-14 21:39:28 -05:00
|
|
|
auto nextBlock = m_blocks[*nextBlockId];
|
|
|
|
while(nextBlock != nullptr)
|
2011-02-26 22:42:59 +00:00
|
|
|
{
|
|
|
|
uint32 end = nextBlock->address;
|
|
|
|
if(begin > wantedAddress)
|
|
|
|
{
|
|
|
|
//Couldn't find suitable space
|
2016-02-14 21:39:28 -05:00
|
|
|
nextBlock = nullptr;
|
2011-02-26 22:42:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(
|
2018-04-30 21:01:23 +01:00
|
|
|
(begin <= wantedAddress) &&
|
2021-08-30 14:10:03 -04:00
|
|
|
(wantedAddress < end) &&
|
2018-04-30 21:01:23 +01:00
|
|
|
((end - begin) >= size))
|
2011-02-26 22:42:59 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
begin = nextBlock->address + nextBlock->size;
|
2016-02-28 15:50:04 -05:00
|
|
|
nextBlockId = &nextBlock->nextBlockId;
|
2011-02-26 22:42:59 +00:00
|
|
|
nextBlock = m_blocks[*nextBlockId];
|
|
|
|
}
|
2018-04-30 21:01:23 +01:00
|
|
|
|
2016-02-14 21:39:28 -05:00
|
|
|
if(nextBlock != nullptr)
|
2009-02-03 19:17:16 +00:00
|
|
|
{
|
2011-02-26 22:42:59 +00:00
|
|
|
uint32 newBlockId = m_blocks.Allocate();
|
2016-02-28 15:50:04 -05:00
|
|
|
assert(newBlockId != BlockListType::INVALID_ID);
|
|
|
|
if(newBlockId == BlockListType::INVALID_ID)
|
2011-02-26 22:42:59 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2016-02-14 21:39:28 -05:00
|
|
|
auto newBlock = m_blocks[newBlockId];
|
2018-04-30 21:01:23 +01:00
|
|
|
newBlock->address = wantedAddress;
|
|
|
|
newBlock->size = size;
|
|
|
|
newBlock->nextBlockId = *nextBlockId;
|
2011-02-26 22:42:59 +00:00
|
|
|
*nextBlockId = newBlockId;
|
|
|
|
return wantedAddress + m_memoryBegin;
|
2009-02-03 19:17:16 +00:00
|
|
|
}
|
2011-02-26 22:42:59 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(0);
|
2009-02-03 19:17:16 +00:00
|
|
|
}
|
|
|
|
|
2011-02-26 22:42:59 +00:00
|
|
|
assert(0);
|
2015-10-23 23:18:32 -04:00
|
|
|
return 0;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CSysmem::FreeMemory(uint32 address)
|
|
|
|
{
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "FreeMemory(address = 0x%08X);\r\n", address);
|
2014-07-10 23:34:01 -04:00
|
|
|
|
2012-09-16 00:28:14 +00:00
|
|
|
address -= m_memoryBegin;
|
2009-02-03 19:17:16 +00:00
|
|
|
//Search for block pointing at the address
|
2016-02-26 22:32:40 -05:00
|
|
|
auto nextBlockId = &m_headBlockId;
|
2016-02-14 21:39:28 -05:00
|
|
|
auto nextBlock = m_blocks[*nextBlockId];
|
|
|
|
while(nextBlock != nullptr)
|
2009-02-03 19:17:16 +00:00
|
|
|
{
|
|
|
|
if(nextBlock->address == address)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2016-02-28 15:50:04 -05:00
|
|
|
nextBlockId = &nextBlock->nextBlockId;
|
2009-02-03 19:17:16 +00:00
|
|
|
nextBlock = m_blocks[*nextBlockId];
|
|
|
|
}
|
|
|
|
|
2016-02-14 21:39:28 -05:00
|
|
|
if(nextBlock != nullptr)
|
2009-02-03 19:17:16 +00:00
|
|
|
{
|
|
|
|
m_blocks.Free(*nextBlockId);
|
2016-02-28 15:50:04 -05:00
|
|
|
*nextBlockId = nextBlock->nextBlockId;
|
2022-03-03 13:44:24 -05:00
|
|
|
return 0;
|
2009-02-03 19:17:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-08-10 13:02:21 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Trying to unallocate an unexisting memory block (0x%08X).\r\n", __FUNCTION__, address);
|
2022-03-03 13:44:24 -05:00
|
|
|
return -1;
|
2009-02-03 19:17:16 +00:00
|
|
|
}
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
2008-01-21 04:09:08 +00:00
|
|
|
|
2021-08-30 14:03:19 -04:00
|
|
|
void CSysmem::DumpAllocList()
|
|
|
|
{
|
|
|
|
auto nextBlockId = &m_headBlockId;
|
|
|
|
auto nextBlock = m_blocks[*nextBlockId];
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Alloc List\r\n");
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "------------------------------\r\n");
|
|
|
|
while(nextBlock != nullptr)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "addr: %08X, size: %08X\r\n", nextBlock->address, nextBlock->size);
|
|
|
|
nextBlockId = &nextBlock->nextBlockId;
|
|
|
|
nextBlock = m_blocks[*nextBlockId];
|
|
|
|
}
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "------------------------------\r\n");
|
|
|
|
}
|
|
|
|
|
2008-01-21 04:09:08 +00:00
|
|
|
uint32 CSysmem::SifAllocate(uint32 nSize)
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
uint32 result = AllocateMemory(nSize, 0, 0);
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "result = 0x%08X = Allocate(size = 0x%08X);\r\n",
|
|
|
|
result, nSize);
|
2012-09-16 00:28:14 +00:00
|
|
|
return result;
|
2008-01-21 04:09:08 +00:00
|
|
|
}
|
|
|
|
|
2008-10-20 04:14:13 +00:00
|
|
|
uint32 CSysmem::SifAllocateSystemMemory(uint32 nSize, uint32 nFlags, uint32 nPtr)
|
2008-01-21 04:09:08 +00:00
|
|
|
{
|
2012-09-16 00:28:14 +00:00
|
|
|
uint32 result = AllocateMemory(nSize, nFlags, nPtr);
|
2018-04-30 21:01:23 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "result = 0x%08X = AllocateSystemMemory(flags = 0x%08X, size = 0x%08X, ptr = 0x%08X);\r\n",
|
|
|
|
result, nFlags, nSize, nPtr);
|
2008-10-20 04:14:13 +00:00
|
|
|
return result;
|
2008-01-21 04:09:08 +00:00
|
|
|
}
|
2008-12-05 03:30:01 +00:00
|
|
|
|
2014-11-08 21:53:56 -05:00
|
|
|
uint32 CSysmem::SifLoadMemory(uint32 address, const char* filePath)
|
|
|
|
{
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "LoadMemory(address = 0x%08X, filePath = '%s');\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
address, filePath);
|
2014-11-08 21:53:56 -05:00
|
|
|
|
|
|
|
auto fd = m_ioman.Open(Ioman::CDevice::OPEN_FLAG_RDONLY, filePath);
|
|
|
|
if(static_cast<int32>(fd) < 0)
|
|
|
|
{
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
uint32 fileSize = m_ioman.Seek(fd, 0, CIoman::SEEK_DIR_END);
|
|
|
|
m_ioman.Seek(fd, 0, CIoman::SEEK_DIR_SET);
|
|
|
|
m_ioman.Read(fd, fileSize, m_iopRam + address);
|
|
|
|
m_ioman.Close(fd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-05 03:30:01 +00:00
|
|
|
uint32 CSysmem::SifFreeMemory(uint32 address)
|
|
|
|
{
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "FreeMemory(address = 0x%08X);\r\n", address);
|
2022-03-03 13:44:24 -05:00
|
|
|
return FreeMemory(address);
|
2008-12-05 03:30:01 +00:00
|
|
|
}
|