s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry) { sysPrxForUser.warning("sys_raw_spu_load(id=%d, path=*0x%x, entry=*0x%x)", id, path, entry); sysPrxForUser.warning("*** path = '%s'", path.get_ptr()); vfsFile f(path.get_ptr()); if (!f.IsOpened()) { sysPrxForUser.error("sys_raw_spu_load error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } SceHeader hdr; hdr.Load(f); if (hdr.CheckMagic()) { sysPrxForUser.error("sys_raw_spu_load error: '%s' is encrypted! Decrypt SELF and try again.", path.get_ptr()); Emu.Pause(); return CELL_ENOENT; } f.Seek(0); u32 _entry; LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id); *entry = _entry | 1; return CELL_OK; }
s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd) { sys_fs.Warning("sys_fs_opendir(path=*0x%x, fd=*0x%x)", path, fd); sys_fs.Warning("*** path = '%s'", path.get_ptr()); std::shared_ptr<vfsDirBase> dir(Emu.GetVFS().OpenDir(path.get_ptr())); if (!dir || !dir->IsOpened()) { sys_fs.Error("sys_fs_opendir('%s'): failed to open directory", path.get_ptr()); return CELL_FS_ENOENT; } for (u32 i = 3; i < g_fds.size(); i++) { // try to reserve fd if (g_fds[i].compare_and_swap_test(0, ~0)) { g_fds[i].store(Emu.GetIdManager().make<lv2_dir_t>(std::move(dir))); *fd = i; return CELL_OK; } } // out of file descriptors return CELL_FS_EMFILE; }
void _Assert(vm::cptr<char> text, vm::cptr<char> func) { sceLibc.error("_Assert(text=*0x%x, func=*0x%x)", text, func); LOG_FATAL(HLE, "%s : %s\n", func.get_ptr(), text.get_ptr()); Emu.Pause(); }
s32 sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path) { sys_spu.Warning("sys_spu_image_open(img_addr=0x%x, path_addr=0x%x [%s])", img.addr(), path.addr(), path.get_ptr()); vfsFile f(path.get_ptr()); if(!f.IsOpened()) { sys_spu.Error("sys_spu_image_open error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } SceHeader hdr; hdr.Load(f); if (hdr.CheckMagic()) { sys_spu.Error("sys_spu_image_open error: '%s' is encrypted! Decrypt SELF and try again.", path.get_ptr()); Emu.Pause(); return CELL_ENOENT; } f.Seek(0); u32 entry; u32 offset = LoadSpuImage(f, entry); img->type = SYS_SPU_IMAGE_TYPE_USER; img->entry_point = entry; img->addr = offset; // TODO: writing actual segment info img->nsegs = 1; // wrong value return CELL_OK; }
s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb) { sys_fs.Warning("sys_fs_stat(path=*0x%x, sb=*0x%x)", path, sb); sys_fs.Warning("*** path = '%s'", path.get_ptr()); std::string local_path; if (!Emu.GetVFS().GetDevice(path.get_ptr(), local_path)) { sys_fs.Warning("sys_fs_stat('%s') failed: not mounted", path.get_ptr()); return CELL_FS_ENOTMOUNTED; } fs::stat_t info; if (!fs::stat(local_path, info)) { sys_fs.Error("sys_fs_stat('%s') failed: not found", path.get_ptr()); return CELL_FS_ENOENT; } sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; sb->uid = 1; // ??? sb->gid = 1; // ??? sb->atime = info.atime; sb->mtime = info.mtime; sb->ctime = info.ctime; sb->size = info.size; sb->blksize = 4096; // ??? return CELL_OK; }
s32 sys_spu_image_open(vm::ptr<sys_spu_image_t> img, vm::cptr<char> path) { sys_spu.warning("sys_spu_image_open(img=*0x%x, path=*0x%x)", img, path); const fs::file f(vfs::get(path.get_ptr())); if (!f) { sys_spu.error("sys_spu_image_open() error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } SceHeader hdr; hdr.Load(f); if (hdr.CheckMagic()) { throw fmt::exception("sys_spu_image_open() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr()); } f.seek(0); u32 entry; u32 offset = LoadSpuImage(f, entry); img->type = SYS_SPU_IMAGE_TYPE_USER; img->entry_point = entry; img->segs.set(offset); // TODO: writing actual segment info img->nsegs = 1; // wrong value return CELL_OK; }
s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry) { sysPrxForUser.warning("sys_raw_spu_load(id=%d, path=*0x%x, entry=*0x%x)", id, path, entry); sysPrxForUser.warning("*** path = '%s'", path.get_ptr()); const fs::file f(vfs::get(path.get_ptr())); if (!f) { sysPrxForUser.error("sys_raw_spu_load() error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } SceHeader hdr; hdr.Load(f); if (hdr.CheckMagic()) { throw fmt::exception("sys_raw_spu_load() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr()); } f.seek(0); u32 _entry; LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id); *entry = _entry | 1; return CELL_OK; }
s32 sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to) { sys_fs.Warning("sys_fs_rename(from=*0x%x, to=*0x%x)", from, to); sys_fs.Warning("*** from = '%s'", from.get_ptr()); sys_fs.Warning("*** to = '%s'", to.get_ptr()); std::string ps3_path = from.get_ptr(); if (Emu.GetVFS().ExistsDir(ps3_path)) { if (!Emu.GetVFS().RenameDir(ps3_path, to.get_ptr())) { return CELL_FS_EIO; // ??? } sys_fs.Notice("sys_fs_rename(): directory '%s' renamed to '%s'", from.get_ptr(), to.get_ptr()); return CELL_OK; } if (Emu.GetVFS().ExistsFile(ps3_path)) { if (!Emu.GetVFS().RenameFile(ps3_path, to.get_ptr())) { return CELL_FS_EIO; // ??? } sys_fs.Notice("sys_fs_rename(): file '%s' renamed to '%s'", from.get_ptr(), to.get_ptr()); return CELL_OK; } return CELL_FS_ENOENT; }
error_code sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to) { sys_fs.warning("sys_fs_rename(from=%s, to=%s)", from, to); if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr()))) { return CELL_ENOENT; // ??? } sys_fs.notice("sys_fs_rename(): %s renamed to %s", from, to); return CELL_OK; }
s32 L10nConvertStr(s32 src_code, vm::cptr<void> src, vm::ptr<u32> src_len, s32 dst_code, vm::ptr<void> dst, vm::ptr<u32> dst_len) { cellL10n.Error("L10nConvertStr(src_code=%d, srca=*0x%x, src_len=*0x%x, dst_code=%d, dst=*0x%x, dst_len=*0x%x)", src_code, src, src_len, dst_code, dst, dst_len); #ifdef _MSC_VER u32 srcCode = 0, dstCode = 0; //OEM code pages bool src_page_converted = _L10nCodeParse(src_code, srcCode); //Check if code is in list. bool dst_page_converted = _L10nCodeParse(dst_code, dstCode); if (((!src_page_converted) && (srcCode == 0)) || ((!dst_page_converted) && (dstCode == 0))) return ConverterUnknown; //if (strnlen_s((char*)src, *src_len) != *src_len) return SRCIllegal; std::string wrapped_source = (char*)src.get_ptr(); //std::string wrapped_source((char*)src); if (wrapped_source.length() != *src_len) return SRCIllegal; std::string target = _OemToOem(srcCode, dstCode, wrapped_source); if (target.length() > *dst_len) return DSTExhausted; memcpy(dst.get_ptr(), target.c_str(), target.size()); return ConversionOK; #else std::string srcCode, dstCode; s32 retValue = ConversionOK; if ((_L10nCodeParse(src_code, srcCode)) && (_L10nCodeParse(dst_code, dstCode))) { iconv_t ict = iconv_open(srcCode.c_str(), dstCode.c_str()); char *srcBuf = (char*)src.get_ptr(); char *dstBuf = (char*)dst.get_ptr(); //char *srcBuf = (char*)src, *dstBuf = (char*)dst; //size_t srcLen = *src_len, dstLen = *dst_len; size_t srcLen = *src_len, dstLen = *dst_len; size_t ictd = iconv(ict, &srcBuf, &srcLen, &dstBuf, &dstLen); if (ictd != *src_len)//if (ictd != *src_len) { if (errno == EILSEQ) retValue = SRCIllegal; //Invalid multi-byte sequence else if (errno == E2BIG) retValue = DSTExhausted;//Not enough space else if (errno == EINVAL) retValue = SRCIllegal; } iconv_close(ict); //retValue = ConversionOK; } else retValue = ConverterUnknown; return retValue; #endif }
s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr<void> pArgBlock) { sceLibKernel.Warning("sceKernelStartThread(threadId=0x%x, argSize=0x%x, pArgBlock=*0x%x)", threadId, argSize, pArgBlock); const auto thread = idm::get<ARMv7Thread>(threadId); if (!thread) { return SCE_KERNEL_ERROR_INVALID_UID; } // thread should be in DORMANT state, but it's not possible to check it correctly atm //if (thread->IsAlive()) //{ // return SCE_KERNEL_ERROR_NOT_DORMANT; //} // push arg block onto the stack const u32 pos = (thread->SP -= argSize); std::memcpy(vm::base(pos), pArgBlock.get_ptr(), argSize); // set SceKernelThreadEntry function arguments thread->GPR[0] = argSize; thread->GPR[1] = pos; thread->exec(); return SCE_OK; }
error_code cellGameSetParamString(s32 id, vm::cptr<char> buf) { cellGame.warning("cellGameSetParamString(id=%d, buf=*0x%x)", id, buf); const auto prm = fxm::get<content_permission>(); if (!prm) { return CELL_GAME_ERROR_FAILURE; } const auto key = get_param_string_key(id); if (!key) { return CELL_GAME_ERROR_INVALID_ID; } u32 max_size = CELL_GAME_SYSP_TITLE_SIZE; switch (id) { case CELL_GAME_PARAMID_TITLE_ID: max_size = CELL_GAME_SYSP_TITLEID_SIZE; break; case CELL_GAME_PARAMID_VERSION: max_size = CELL_GAME_SYSP_VERSION_SIZE; break; case CELL_GAME_PARAMID_PS3_SYSTEM_VER: max_size = CELL_GAME_SYSP_PS3_SYSTEM_VER_SIZE; break; case CELL_GAME_PARAMID_APP_VER: max_size = CELL_GAME_SYSP_APP_VER_SIZE; break; } prm->sfo.emplace(key, psf::string(max_size, buf.get_ptr())); return CELL_OK; }
s32 _L10nConvertStr(s32 src_code, vm::cptr<void> src, vm::cptr<s32> src_len, s32 dst_code, vm::ptr<void> dst, vm::ptr<s32> dst_len) { s32 dstLen = *dst_len; s32 result = _ConvertStr(src_code, src.get_ptr(), *src_len, dst_code, dst == vm::null ? NULL : dst.get_ptr(), &dstLen, false); *dst_len = dstLen; return result; }
error_code sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen) { sys_tty.notice("sys_tty_write(ch=%d, buf=*0x%x, len=%d, pwritelen=*0x%x)", ch, buf, len, pwritelen); if (ch > 15) { return CELL_EINVAL; } const u32 written_len = static_cast<s32>(len) > 0 ? len : 0; if (written_len > 0 && g_tty) { // Lock size by making it negative g_tty_size -= (1ll << 48); g_tty.write(buf.get_ptr(), len); g_tty_size += (1ll << 48) + len; } if (!pwritelen) { return CELL_EFAULT; } *pwritelen = written_len; return CELL_OK; }
s32 bind(s32 s, vm::cptr<sockaddr> addr, u32 addrlen) { libnet.warning("bind(s=%d, family=*0x%x, addrlen=%d)", s, addr, addrlen); std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s); if (!sock) { libnet.error("bind(): socket does not exist"); return -1; } ::sockaddr_in saddr; memcpy(&saddr, addr.get_ptr(), sizeof(::sockaddr_in)); saddr.sin_family = addr->sa_family; const char *ipaddr = ::inet_ntoa(saddr.sin_addr); libnet.warning("binding to %s on port %d", ipaddr, ntohs(saddr.sin_port)); s32 ret = ::bind(sock->s, (const ::sockaddr*)&saddr, addrlen); if (ret != 0) { libnet.error("bind(): error %d", get_errno() = get_last_error()); return -1; } return ret; }
s32 cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char> dirName) { cellGame.Warning("cellGameContentErrorDialog(type=%d, errNeedSizeKB=%d, dirName=*0x%x)", type, errNeedSizeKB, dirName); std::string errorName; switch (type) { case CELL_GAME_ERRDIALOG_BROKEN_GAMEDATA: errorName = "Game data is corrupted (can be continued)."; break; case CELL_GAME_ERRDIALOG_BROKEN_HDDGAME: errorName = "HDD boot game is corrupted (can be continued)."; break; case CELL_GAME_ERRDIALOG_NOSPACE: errorName = "Not enough available space (can be continued)."; break; case CELL_GAME_ERRDIALOG_BROKEN_EXIT_GAMEDATA: errorName = "Game data is corrupted (terminate application)."; break; case CELL_GAME_ERRDIALOG_BROKEN_EXIT_HDDGAME: errorName = "HDD boot game is corrupted (terminate application)."; break; case CELL_GAME_ERRDIALOG_NOSPACE_EXIT: errorName = "Not enough available space (terminate application)."; break; default: return CELL_GAME_ERROR_PARAM; } std::string errorMsg; if (type == CELL_GAME_ERRDIALOG_NOSPACE || type == CELL_GAME_ERRDIALOG_NOSPACE_EXIT) { errorMsg = fmt::format("ERROR: %s\nSpace needed: %d KB", errorName, errNeedSizeKB); } else { errorMsg = fmt::format("ERROR: %s", errorName); } if (dirName) { errorMsg += fmt::Format("\nDirectory name: %s", dirName.get_ptr()); } rMessageBox(errorMsg, "Error", rICON_ERROR | rOK); return CELL_OK; }
error_code sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb) { sys_fs.warning("sys_fs_stat(path=%s, sb=*0x%x)", path, sb); const std::string& local_path = vfs::get(path.get_ptr()); if (local_path.empty()) { sys_fs.warning("sys_fs_stat(%s) failed: not mounted", path); return CELL_ENOTMOUNTED; } fs::stat_t info; if (!fs::stat(local_path, info)) { sys_fs.error("sys_fs_stat(%s) failed: not found", path); return CELL_ENOENT; } sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; sb->uid = 1; // ??? sb->gid = 1; // ??? sb->atime = info.atime; sb->mtime = info.mtime; sb->ctime = info.ctime; sb->size = info.size; sb->blksize = 4096; // ??? return CELL_OK; }
s32 cellFsWriteWithOffset(u32 fd, u64 offset, vm::cptr<void> buf, u64 data_size, vm::ptr<u64> nwrite) { cellFs.Log("cellFsWriteWithOffset(fd=%d, offset=0x%llx, buf=*0x%x, data_size=0x%llx, nwrite=*0x%x)", fd, offset, buf, data_size, nwrite); // TODO: use single sys_fs_fcntl syscall const auto file = idm::get<lv2_file_t>(fd); if (!file || !(file->flags & CELL_FS_O_ACCMODE)) { return CELL_FS_EBADF; } std::lock_guard<std::mutex> lock(file->mutex); const auto old_position = file->file->Tell(); file->file->Seek(offset); const auto written = file->file->Write(buf.get_ptr(), data_size); file->file->Seek(old_position); if (nwrite) { *nwrite = written; } return CELL_OK; }
error_code sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen) { sys_tty.notice("sys_tty_write(ch=%d, buf=*0x%x, len=%d, pwritelen=*0x%x)", ch, buf, len, pwritelen); if (ch > 15) { return CELL_EINVAL; } if (static_cast<s32>(len) <= 0) { *pwritelen = 0; return CELL_OK; } if (g_tty) { g_tty.write(buf.get_ptr(), len); } *pwritelen = len; return CELL_OK; }
s32 sys_fs_chmod(vm::cptr<char> path, s32 mode) { sys_fs.Todo("sys_fs_chmod(path=*0x%x, mode=%#o) -> CELL_OK", path, mode); sys_fs.Todo("*** path = '%s'", path.get_ptr()); return CELL_OK; }
vm::ptr<void> _sys_memcpy(vm::ptr<void> dst, vm::cptr<void> src, u32 size) { sysPrxForUser.trace("_sys_memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size); memcpy(dst.get_ptr(), src.get_ptr(), size); return dst; }
s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd) { sys_fs.Warning("sys_fs_opendir(path=*0x%x, fd=*0x%x)", path, fd); sys_fs.Warning("*** path = '%s'", path.get_ptr()); std::shared_ptr<vfsDirBase> dir(Emu.GetVFS().OpenDir(path.get_ptr())); if (!dir || !dir->IsOpened()) { sys_fs.Error("sys_fs_opendir('%s'): failed to open directory", path.get_ptr()); return CELL_FS_ENOENT; } *fd = Emu.GetIdManager().make<lv2_dir_t>(std::move(dir)); return CELL_OK; }
vm::ptr<void> _sys_memmove(vm::ptr<void> dst, vm::cptr<void> src, u32 size) { sysPrxForUser.trace("_sys_memmove(dst=*0x%x, src=*0x%x, size=%d)", dst, src, size); std::memmove(dst.get_ptr(), src.get_ptr(), size); return dst; }
vm::ptr<char> _sys_strncat(vm::ptr<char> dest, vm::cptr<char> source, u32 len) { sysPrxForUser.trace("_sys_strncat(dest=*0x%x, source=%s, len=%d)", dest, source, len); verify(HERE), std::strncat(dest.get_ptr(), source.get_ptr(), len) == dest.get_ptr(); return dest; }
vm::ptr<char> _sys_strcpy(vm::ptr<char> dest, vm::cptr<char> source) { sysPrxForUser.trace("_sys_strcpy(dest=*0x%x, source=%s)", dest, source); verify(HERE), std::strcpy(dest.get_ptr(), source.get_ptr()) == dest.get_ptr(); return dest; }
static std::string ps3_fmt(ppu_thread& context, vm::cptr<char> fmt, u32 g_count) { std::string result; cfmt_append(result, fmt.get_ptr(), ps3_fmt_src{&context, g_count}); return result; }
s32 send(s32 s, vm::cptr<char> buf, u32 len, s32 flags) { sys_net.Warning("send(s=%d, buf=*0x%x, len=%d, flags=0x%x)", s, buf, len, flags); int ret = ::send(s, buf.get_ptr(), len, flags); *g_lastError = getLastError(); return ret; }
s32 setsockopt(s32 s, s32 level, s32 optname, vm::cptr<char> optval, u32 optlen) { sys_net.Warning("socket(s=%d, level=%d, optname=%d, optval=*0x%x, optlen=%d)", s, level, optname, optval, optlen); int ret = ::setsockopt(s, level, optname, optval.get_ptr(), optlen); *g_lastError = getLastError(); return ret; }
s32 cellGameDataCheck(u32 type, vm::cptr<char> dirName, vm::ptr<CellGameContentSize> size) { cellGame.Warning("cellGameDataCheck(type=%d, dirName=*0x%x, size=*0x%x)", type, dirName, size); if ((type - 1) >= 3) { cellGame.Error("cellGameDataCheck(): CELL_GAME_ERROR_PARAM"); return CELL_GAME_ERROR_PARAM; } if (size) { // TODO: Use the free space of the computer's HDD where RPCS3 is being run. size->hddFreeSizeKB = 40000000; //40 GB // TODO: Calculate data size for game data, if necessary. size->sizeKB = CELL_GAME_SIZEKB_NOTCALC; size->sysSizeKB = 0; } if (type == CELL_GAME_GAMETYPE_DISC) { // TODO: not sure what should be checked there if (!Emu.GetVFS().ExistsDir("/dev_bdvd/PS3_GAME")) { cellGame.Warning("cellGameDataCheck(): /dev_bdvd/PS3_GAME not found"); contentInfo = ""; usrdir = ""; path_set = true; return CELL_GAME_RET_NONE; } contentInfo = "/dev_bdvd/PS3_GAME"; usrdir = "/dev_bdvd/PS3_GAME/USRDIR"; path_set = true; } else { const std::string dir = std::string("/dev_hdd0/game/") + dirName.get_ptr(); if (!Emu.GetVFS().ExistsDir(dir)) { cellGame.Warning("cellGameDataCheck(): '%s' directory not found", dir.c_str()); contentInfo = ""; usrdir = ""; path_set = true; return CELL_GAME_RET_NONE; } contentInfo = dir; usrdir = dir + "/USRDIR"; path_set = true; } return CELL_GAME_RET_OK; }
s32 cellFsAioFinish(vm::cptr<char> mount_point) { cellFs.Warning("cellFsAioFinish(mount_point=*0x%x)", mount_point); cellFs.Warning("*** mount_point = '%s'", mount_point.get_ptr()); // TODO: delete existing AIO thread for specified mount point return CELL_OK; }