Implements sys_fs_fcntl 0xC0000008 & 0xC000001A (#11957)

This commit is contained in:
RipleyTom 2022-06-11 14:12:42 +02:00 committed by GitHub
parent a2623b1a9a
commit da6434a65a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 188 additions and 21 deletions

View File

@ -1850,7 +1850,7 @@ bool ppu_load_exec(const ppu_exec_object& elf)
g_fxo->init<lv2_memory_container>(mem_size);
}
g_fxo->get<lv2_memory_container>().used += primary_stacksize;
ensure(g_fxo->get<lv2_memory_container>().take(primary_stacksize));
ppu->cmd_push({ppu_cmd::initialize, 0});

View File

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "sys_sync.h"
#include "sys_fs.h"
#include "sys_memory.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/PPUThread.h"
@ -865,6 +866,22 @@ error_code sys_fs_close(ppu_thread& ppu, u32 fd)
sys_fs.warning("%s: %s", FD_state_log, *file);
}
// Free memory associated with fd if any
if (file->ct_id && file->ct_used)
{
auto& default_container = g_fxo->get<default_sys_fs_container>();
std::lock_guard lock(default_container.mutex);
if (auto ct = idm::get<lv2_memory_container>(file->ct_id))
{
ct->free(file->ct_used);
if (default_container.id == file->ct_id)
{
default_container.used -= file->ct_used;
}
}
}
// Ensure Host file handle won't be kept open after this syscall
file->file.close();
}
@ -1653,7 +1670,7 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
case 0xc0000007: // cellFsArcadeHddSerialNumber
{
const auto arg = vm::static_ptr_cast<lv2_file_c000007>(_arg);
const auto arg = vm::static_ptr_cast<lv2_file_c0000007>(_arg);
// TODO populate arg-> unk1+2
arg->out_code = CELL_OK;
return CELL_OK;
@ -1661,7 +1678,86 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
case 0xc0000008: // cellFsSetDefaultContainer, cellFsSetIoBuffer, cellFsSetIoBufferFromDefaultContainer
{
break;
// Allocates memory from a container/default container to a specific fd or default IO processing
const auto arg = vm::static_ptr_cast<lv2_file_c0000008>(_arg);
auto& default_container = g_fxo->get<default_sys_fs_container>();
std::lock_guard def_container_lock(default_container.mutex);
if (fd == 0xFFFFFFFF)
{
// No check on container is done when setting default container
default_container.id = arg->size ? ::narrow<u32>(arg->container_id) : 0u;
default_container.cap = arg->size;
default_container.used = 0;
arg->out_code = CELL_OK;
return CELL_OK;
}
auto file = idm::get<lv2_fs_object, lv2_file>(fd);
if (!file)
{
return CELL_EBADF;
}
if (auto ct = idm::get<lv2_memory_container>(file->ct_id))
{
ct->free(file->ct_used);
if (default_container.id == file->ct_id)
{
default_container.used -= file->ct_used;
}
}
file->ct_id = 0;
file->ct_used = 0;
// Aligns on lower bound
u32 actual_size = arg->size - (arg->size % ((arg->page_type & CELL_FS_IO_BUFFER_PAGE_SIZE_64KB) ? 0x10000 : 0x100000));
if (!actual_size)
{
arg->out_code = CELL_OK;
return CELL_OK;
}
u32 new_container_id = arg->container_id == 0xFFFFFFFF ? default_container.id : ::narrow<u32>(arg->container_id);
if (default_container.id == new_container_id && (default_container.used + actual_size) > default_container.cap)
{
return CELL_ENOMEM;
}
const auto ct = idm::get<lv2_memory_container>(new_container_id, [&](lv2_memory_container& ct) -> CellError
{
if (!ct.take(actual_size))
{
return CELL_ENOMEM;
}
return {};
});
if (!ct)
{
return CELL_ESRCH;
}
if (ct.ret)
{
return ct.ret;
}
if (default_container.id == new_container_id)
{
default_container.used += actual_size;
}
file->ct_id = new_container_id;
file->ct_used = actual_size;
arg->out_code = CELL_OK;
return CELL_OK;
}
case 0xc0000015: // USB Vid/Pid lookup - Used by arcade games on dev_usbXXX
@ -1735,7 +1831,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
case 0xc000001a: // cellFsSetDiscReadRetrySetting, 5731DF45
{
break;
[[maybe_unused]] const auto arg = vm::static_ptr_cast<lv2_file_c000001a>(_arg);
return CELL_OK;
}
case 0xc000001c: // USB Vid/Pid/Serial lookup

View File

@ -67,6 +67,12 @@ enum : u8
CELL_FS_TYPE_SYMLINK = 3,
};
enum : u32
{
CELL_FS_IO_BUFFER_PAGE_SIZE_64KB = 0x0002,
CELL_FS_IO_BUFFER_PAGE_SIZE_1MB = 0x0004,
};
struct CellFsDirent
{
u8 d_type;
@ -203,6 +209,9 @@ struct lv2_file final : lv2_fs_object
std::string real_path;
const lv2_file_type type;
// IO Container
u32 ct_id{}, ct_used{};
// Stream lock
atomic_t<u32> lock{0};
@ -435,7 +444,7 @@ struct lv2_file_c0000006 : lv2_file_op
CHECK_SIZE(lv2_file_c0000006, 0x20);
struct lv2_file_c000007 : lv2_file_op
struct lv2_file_c0000007 : lv2_file_op
{
be_t<u32> out_code;
vm::bcptr<char> name;
@ -446,7 +455,24 @@ struct lv2_file_c000007 : lv2_file_op
be_t<u32> unk2_size; //0x21
};
CHECK_SIZE(lv2_file_c000007, 0x1c);
CHECK_SIZE(lv2_file_c0000007, 0x1c);
struct lv2_file_c0000008 : lv2_file_op
{
u8 _x0[4];
be_t<u32> op; // 0xC0000008
u8 _x8[8];
be_t<u64> container_id;
be_t<u32> size;
be_t<u32> page_type; // 0x4000 for cellFsSetDefaultContainer
// 0x4000 | page_type given by user, valid values seem to be:
// CELL_FS_IO_BUFFER_PAGE_SIZE_64KB 0x0002
// CELL_FS_IO_BUFFER_PAGE_SIZE_1MB 0x0004
be_t<u32> out_code;
u8 _x24[4];
};
CHECK_SIZE(lv2_file_c0000008, 0x28);
struct lv2_file_c0000015 : lv2_file_op
{
@ -463,6 +489,19 @@ struct lv2_file_c0000015 : lv2_file_op
CHECK_SIZE(lv2_file_c0000015, 0x20);
struct lv2_file_c000001a : lv2_file_op
{
be_t<u32> disc_retry_type; // CELL_FS_DISC_READ_RETRY_NONE results in a 0 here
// CELL_FS_DISC_READ_RETRY_DEFAULT results in a 0x63 here
be_t<u32> _x4; // 0
be_t<u32> _x8; // 0x000186A0
be_t<u32> _xC; // 0
be_t<u32> _x10; // 0
be_t<u32> _x14; // 0
};
CHECK_SIZE(lv2_file_c000001a, 0x18);
struct lv2_file_c000001c : lv2_file_op
{
be_t<u32> size; // 0x20
@ -507,6 +546,18 @@ struct CellFsMountInfo
CHECK_SIZE(CellFsMountInfo, 0x94);
// Default IO container
struct default_sys_fs_container
{
default_sys_fs_container(const default_sys_fs_container&) = delete;
default_sys_fs_container& operator=(const default_sys_fs_container&) = delete;
shared_mutex mutex;
u32 id = 0;
u32 cap = 0;
u32 used = 0;
};
// Syscalls
error_code sys_fs_test(ppu_thread& ppu, u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> buf, u32 buf_size);

View File

@ -83,7 +83,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32
}
}
dct.used -= size;
dct.free(size);
return CELL_ENOMEM;
}
@ -154,7 +154,7 @@ error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid
}
}
ct->used -= size;
ct->free(size);
return CELL_ENOMEM;
}
@ -172,7 +172,7 @@ error_code sys_memory_free(cpu_thread& cpu, u32 addr)
}
const auto size = (ensure(vm::dealloc(addr)));
reader_lock{id_manager::g_mutex}, ct->used -= size;
reader_lock{id_manager::g_mutex}, ct->free(size);
return CELL_OK;
}
@ -277,7 +277,7 @@ error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u32 si
return CELL_OK;
}
dct.used -= size;
dct.free(size);
return CELL_EAGAIN;
}
@ -311,7 +311,7 @@ error_code sys_memory_container_destroy(cpu_thread& cpu, u32 cid)
}
// Return "physical memory" to the default container
g_fxo->get<lv2_memory_container>().used -= ct->size;
g_fxo->get<lv2_memory_container>().free(ct->size);
return CELL_OK;
}

View File

@ -89,6 +89,25 @@ struct lv2_memory_container
return result;
}
u32 free(u64 amount)
{
auto [_, result] = used.fetch_op([&](u32& value) -> u32
{
if (value >= amount)
{
value -= static_cast<u32>(amount);
return static_cast<u32>(amount);
}
return 0;
});
// Sanity check
ensure(result == amount);
return result;
}
};
struct sys_memory_user_memory_stat_t

View File

@ -529,7 +529,7 @@ error_code sys_mmapper_free_shared_memory(ppu_thread& ppu, u32 mem_id)
if (!mem.exists)
{
// Return "physical memory" to the memory container
mem.ct->used -= mem.size;
mem.ct->free(mem.size);
}
return {};

View File

@ -45,7 +45,7 @@ void ppu_thread_exit(ppu_thread& ppu, ppu_opcode_t, be_t<u32>*, struct ppu_intrp
if (auto& dct = g_fxo->get<lv2_memory_container>(); !Emu.IsStopped())
{
dct.used -= ppu.stack_size;
dct.free(ppu.stack_size);
}
if (ppu.call_history.index)
@ -418,7 +418,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::p
if (!stack_base)
{
dct.used -= stack_size;
dct.free(stack_size);
return CELL_ENOMEM;
}
@ -447,7 +447,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::p
if (!tid)
{
vm::dealloc(stack_base);
dct.used -= stack_size;
dct.free(stack_size);
return CELL_EAGAIN;
}

View File

@ -780,7 +780,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
if (!limits.check(use_scheduler ? limits_data{.controllable = num} : limits_data{.physical = num}))
{
ct->used -= mem_size;
ct->free(mem_size);
return CELL_EBUSY;
}
@ -788,7 +788,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
if (!group)
{
ct->used -= mem_size;
ct->free(mem_size);
return CELL_EAGAIN;
}
@ -823,7 +823,7 @@ error_code sys_spu_thread_group_destroy(ppu_thread& ppu, u32 id)
return CELL_EBUSY;
}
group.ct->used -= group.mem_size;
group.ct->free(group.mem_size);
return {};
});

View File

@ -85,7 +85,7 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
return CELL_OK;
}
ct->used -= psize;
ct->free(psize);
g_fxo->get<sys_vm_global_t>().total_vsize -= vsize;
return CELL_ENOMEM;
}
@ -119,7 +119,7 @@ error_code sys_vm_unmap(ppu_thread& ppu, u32 addr)
ensure(vm::unmap(addr).second);
// Return memory
vmo.ct->used -= vmo.psize;
vmo.ct->free(vmo.psize);
g_fxo->get<sys_vm_global_t>().total_vsize -= vmo.size;
});
@ -205,7 +205,7 @@ error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size)
return CELL_EBUSY;
}
vmo.ct->used -= size;
vmo.ct->free(size);
return {};
});