diff --git a/pcsx2/IopBios.cpp b/pcsx2/IopBios.cpp index db53907f20..174de4e2c4 100644 --- a/pcsx2/IopBios.cpp +++ b/pcsx2/IopBios.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team + * Copyright (C) 2002-2021 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -26,20 +26,22 @@ #define O_BINARY 0 #endif -typedef struct { - unsigned int mode; - unsigned int attr; - unsigned int size; - unsigned char ctime[8]; - unsigned char atime[8]; - unsigned char mtime[8]; - unsigned int hisize; +typedef struct +{ + unsigned int mode; + unsigned int attr; + unsigned int size; + unsigned char ctime[8]; + unsigned char atime[8]; + unsigned char mtime[8]; + unsigned int hisize; } fio_stat_t; -typedef struct { - fio_stat_t stat; - char name[256]; - unsigned int unknown; +typedef struct +{ + fio_stat_t stat; + char name[256]; + unsigned int unknown; } fio_dirent_t; static char HostRoot[1024]; @@ -48,42 +50,44 @@ void Hle_SetElfPath(const char* elfFileName) { DevCon.WriteLn("HLE Host: Will load ELF: %s\n", elfFileName); - const char* pos1 = strrchr(elfFileName,'/'); - const char* pos2 = strrchr(elfFileName,'\\'); + const char* pos1 = strrchr(elfFileName, '/'); + const char* pos2 = strrchr(elfFileName, '\\'); - if(pos2 > pos1) // we want the LAST path separator - pos1=pos2; + if (pos2 > pos1) // we want the LAST path separator + pos1 = pos2; - if(!pos1) // if pos1 is NULL, then pos2 was not > pos1, so it must also be NULL + if (!pos1) // if pos1 is NULL, then pos2 was not > pos1, so it must also be NULL { Console.WriteLn("HLE Notice: ELF does not have a path.\n"); // use %CD%/host/ - char* cwd = getcwd(HostRoot,1000); // save the other 23 chars to append /host/ :P - HostRoot[1000]=0; // Be Safe. - if (cwd == nullptr) { + char* cwd = getcwd(HostRoot, 1000); // save the other 23 chars to append /host/ :P + HostRoot[1000] = 0; // Be Safe. + if (cwd == nullptr) + { Console.Error("Hle_SetElfPath: getcwd: buffer is too small"); return; } char* last = HostRoot + strlen(HostRoot) - 1; - if((*last!='/') && (*last!='\\')) // PathAppend()-ish + if ((*last != '/') && (*last != '\\')) // PathAppend()-ish last++; - strcpy(last,"/host/"); + strcpy(last, "/host/"); return; } - int len = pos1-elfFileName+1; - memcpy(HostRoot,elfFileName,len); // include the / (or \\) + int len = pos1 - elfFileName + 1; + memcpy(HostRoot, elfFileName, len); // include the / (or \\) HostRoot[len] = 0; - + Console.WriteLn("HLE Host: Set 'host:' root path to: %s\n", HostRoot); } -namespace R3000A { +namespace R3000A +{ #define v0 (psxRegs.GPR.n.v0) #define a0 (psxRegs.GPR.n.a0) @@ -107,652 +111,699 @@ namespace R3000A { #define FIO_SO_IFREG 0x0010 #define FIO_SO_IFDIR 0x0020 -static std::string host_path(const std::string path) -{ - // We are NOT allowing to use the root of the host unit. - // For now it just supports relative folders from the location of the elf - if (path.rfind(HostRoot, 0) == 0) - return path; - else // relative paths - return HostRoot + path; -} + static std::string host_path(const std::string path) + { + // We are NOT allowing to use the root of the host unit. + // For now it just supports relative folders from the location of the elf + if (path.rfind(HostRoot, 0) == 0) + return path; + else // relative paths + return HostRoot + path; + } -static int host_stat(const std::string path, fio_stat_t *host_stats) -{ - struct stat file_stats; - - if (::stat(path.c_str(), &file_stats)) - return -IOP_ENOENT; - - host_stats->size = file_stats.st_size; - host_stats->hisize = 0; - - // Convert the mode. - host_stats->mode = (file_stats.st_mode & (FIO_SO_IROTH | FIO_SO_IWOTH | FIO_SO_IXOTH)); + static int host_stat(const std::string path, fio_stat_t* host_stats) + { + struct stat file_stats; + + if (::stat(path.c_str(), &file_stats)) + return -IOP_ENOENT; + + host_stats->size = file_stats.st_size; + host_stats->hisize = 0; + + // Convert the mode. + host_stats->mode = (file_stats.st_mode & (FIO_SO_IROTH | FIO_SO_IWOTH | FIO_SO_IXOTH)); #ifndef _WIN32 - if (S_ISLNK(file_stats.st_mode)) { host_stats->mode |= FIO_SO_IFLNK; } + if (S_ISLNK(file_stats.st_mode)) + { + host_stats->mode |= FIO_SO_IFLNK; + } #endif - if (S_ISREG(file_stats.st_mode)) { host_stats->mode |= FIO_SO_IFREG; } - if (S_ISDIR(file_stats.st_mode)) { host_stats->mode |= FIO_SO_IFDIR; } - - // Convert the creation time. - struct tm *loctime; - loctime = localtime(&(file_stats.st_ctime)); - host_stats->ctime[6] = (unsigned char)loctime->tm_year; - host_stats->ctime[5] = (unsigned char)loctime->tm_mon + 1; - host_stats->ctime[4] = (unsigned char)loctime->tm_mday; - host_stats->ctime[3] = (unsigned char)loctime->tm_hour; - host_stats->ctime[2] = (unsigned char)loctime->tm_min; - host_stats->ctime[1] = (unsigned char)loctime->tm_sec; - - // Convert the access time. - loctime = localtime(&(file_stats.st_atime)); - host_stats->atime[6] = (unsigned char)loctime->tm_year; - host_stats->atime[5] = (unsigned char)loctime->tm_mon + 1; - host_stats->atime[4] = (unsigned char)loctime->tm_mday; - host_stats->atime[3] = (unsigned char)loctime->tm_hour; - host_stats->atime[2] = (unsigned char)loctime->tm_min; - host_stats->atime[1] = (unsigned char)loctime->tm_sec; - - // Convert the last modified time. - loctime = localtime(&(file_stats.st_mtime)); - host_stats->mtime[6] = (unsigned char)loctime->tm_year; - host_stats->mtime[5] = (unsigned char)loctime->tm_mon + 1; - host_stats->mtime[4] = (unsigned char)loctime->tm_mday; - host_stats->mtime[3] = (unsigned char)loctime->tm_hour; - host_stats->mtime[2] = (unsigned char)loctime->tm_min; - host_stats->mtime[1] = (unsigned char)loctime->tm_sec; - - return 0; -} - -// TODO: sandbox option, other permissions -class HostFile : public IOManFile -{ -public: - int fd; - - HostFile(int hostfd) - { - fd = hostfd; - } - - virtual ~HostFile() = default; - - static __fi int translate_error(int err) - { - if (err >= 0) - return err; - - switch(err) + if (S_ISREG(file_stats.st_mode)) { - case -ENOENT: - return -IOP_ENOENT; - case -EACCES: - return -IOP_EACCES; - case -EISDIR: - return -IOP_EISDIR; - case -EIO: - default: - return -IOP_EIO; + host_stats->mode |= FIO_SO_IFREG; } - } - - static int open(IOManFile **file, const std::string &full_path, s32 flags, u16 mode) - { - const std::string path = full_path.substr(full_path.find(':') + 1); - int native_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; // 0644 - int native_flags = O_BINARY; // necessary in Windows. - - switch(flags&IOP_O_RDWR) + if (S_ISDIR(file_stats.st_mode)) { - case IOP_O_RDONLY: native_flags |= O_RDONLY; break; - case IOP_O_WRONLY: native_flags |= O_WRONLY; break; - case IOP_O_RDWR: native_flags |= O_RDWR; break; + host_stats->mode |= FIO_SO_IFDIR; } - if(flags&IOP_O_APPEND) native_flags |= O_APPEND; - if(flags&IOP_O_CREAT) native_flags |= O_CREAT; - if(flags&IOP_O_TRUNC) native_flags |= O_TRUNC; + // Convert the creation time. + struct tm* loctime; + loctime = localtime(&(file_stats.st_ctime)); + host_stats->ctime[6] = (unsigned char)loctime->tm_year; + host_stats->ctime[5] = (unsigned char)loctime->tm_mon + 1; + host_stats->ctime[4] = (unsigned char)loctime->tm_mday; + host_stats->ctime[3] = (unsigned char)loctime->tm_hour; + host_stats->ctime[2] = (unsigned char)loctime->tm_min; + host_stats->ctime[1] = (unsigned char)loctime->tm_sec; - int hostfd = ::open(host_path(path).data(), native_flags, native_mode); - if (hostfd < 0) - return translate_error(hostfd); + // Convert the access time. + loctime = localtime(&(file_stats.st_atime)); + host_stats->atime[6] = (unsigned char)loctime->tm_year; + host_stats->atime[5] = (unsigned char)loctime->tm_mon + 1; + host_stats->atime[4] = (unsigned char)loctime->tm_mday; + host_stats->atime[3] = (unsigned char)loctime->tm_hour; + host_stats->atime[2] = (unsigned char)loctime->tm_min; + host_stats->atime[1] = (unsigned char)loctime->tm_sec; - *file = new HostFile(hostfd); - if (!*file) - return -IOP_ENOMEM; + // Convert the last modified time. + loctime = localtime(&(file_stats.st_mtime)); + host_stats->mtime[6] = (unsigned char)loctime->tm_year; + host_stats->mtime[5] = (unsigned char)loctime->tm_mon + 1; + host_stats->mtime[4] = (unsigned char)loctime->tm_mday; + host_stats->mtime[3] = (unsigned char)loctime->tm_hour; + host_stats->mtime[2] = (unsigned char)loctime->tm_min; + host_stats->mtime[1] = (unsigned char)loctime->tm_sec; return 0; } - virtual void close() + // TODO: sandbox option, other permissions + class HostFile : public IOManFile { - ::close(fd); - delete this; - } + public: + int fd; - virtual int lseek(s32 offset, s32 whence) - { - int err; - - switch (whence) + HostFile(int hostfd) { - case IOP_SEEK_SET: - err = ::lseek(fd, offset, SEEK_SET); - break; - case IOP_SEEK_CUR: - err = ::lseek(fd, offset, SEEK_CUR); - break; - case IOP_SEEK_END: - err = ::lseek(fd, offset, SEEK_END); - break; - default: - return -IOP_EIO; + fd = hostfd; } - return translate_error(err); - } + virtual ~HostFile() = default; - virtual int read(void *buf, u32 count) - { - return translate_error(::read(fd, buf, count)); - } - - virtual int write(void *buf, u32 count) - { - return translate_error(::write(fd, buf, count)); - } -}; - -class HostDir : public IOManDir -{ -public: - DIR *dir; - std::string path; - - HostDir(DIR *native_dir, const std::string native_path) - { - dir = native_dir; - path = native_path; - } - - virtual ~HostDir() = default; - - static int open(IOManDir** dir, const std::string& full_path) - { - const std::string relativePath = full_path.substr(full_path.find(':') + 1); - const std::string path = host_path(relativePath); - - DIR *dirent = ::opendir(path.c_str()); - if (!dirent) - return -IOP_ENOENT; // Should return ENOTDIR if path is a file? - - *dir = new HostDir(dirent, relativePath); - if (!*dir) - return -IOP_ENOMEM; - - return 0; - } - - virtual int read(void *buf) - { - fio_dirent_t *hostcontent = (fio_dirent_t *)buf; - struct dirent *dire = ::readdir(dir); - - if (dire == NULL) - return 0; - - strcpy(hostcontent->name, dire->d_name); - host_stat(host_path(path + dire->d_name), &hostcontent->stat); - - return 1; - } - - virtual void close() - { - ::closedir(dir); - delete this; - } - -}; - -namespace ioman { - const int firstfd = 0x100; - const int maxfds = 0x100; - int openfds = 0; - - int freefdcount() - { - return maxfds - openfds; - } - - struct filedesc - { - enum { - FILE_FREE, - FILE_FILE, - FILE_DIR, - } type; - union { - IOManFile *file; - IOManDir *dir; - }; - - constexpr filedesc(): type(FILE_FREE), file(nullptr) {} - operator bool() const { return type != FILE_FREE; } - operator IOManFile*() const { return type == FILE_FILE ? file : NULL; } - operator IOManDir*() const { return type == FILE_DIR ? dir : NULL; } - void operator=(IOManFile *f) { type = FILE_FILE; file = f; openfds++; } - void operator=(IOManDir *d) { type = FILE_DIR; dir = d; openfds++; } - - void close() + static __fi int translate_error(int err) { - switch (type) + if (err >= 0) + return err; + + switch (err) { - case FILE_FILE: - file->close(); - file = NULL; + case -ENOENT: + return -IOP_ENOENT; + case -EACCES: + return -IOP_EACCES; + case -EISDIR: + return -IOP_EISDIR; + case -EIO: + default: + return -IOP_EIO; + } + } + + static int open(IOManFile** file, const std::string& full_path, s32 flags, u16 mode) + { + const std::string path = full_path.substr(full_path.find(':') + 1); + int native_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644 + int native_flags = O_BINARY; // necessary in Windows. + + switch (flags & IOP_O_RDWR) + { + case IOP_O_RDONLY: + native_flags |= O_RDONLY; break; - case FILE_DIR: - dir->close(); - dir = NULL; + case IOP_O_WRONLY: + native_flags |= O_WRONLY; + break; + case IOP_O_RDWR: + native_flags |= O_RDWR; break; - case FILE_FREE: - return; } - type = FILE_FREE; - openfds--; + if (flags & IOP_O_APPEND) + native_flags |= O_APPEND; + if (flags & IOP_O_CREAT) + native_flags |= O_CREAT; + if (flags & IOP_O_TRUNC) + native_flags |= O_TRUNC; + + int hostfd = ::open(host_path(path).data(), native_flags, native_mode); + if (hostfd < 0) + return translate_error(hostfd); + + *file = new HostFile(hostfd); + if (!*file) + return -IOP_ENOMEM; + + return 0; + } + + virtual void close() + { + ::close(fd); + delete this; + } + + virtual int lseek(s32 offset, s32 whence) + { + int err; + + switch (whence) + { + case IOP_SEEK_SET: + err = ::lseek(fd, offset, SEEK_SET); + break; + case IOP_SEEK_CUR: + err = ::lseek(fd, offset, SEEK_CUR); + break; + case IOP_SEEK_END: + err = ::lseek(fd, offset, SEEK_END); + break; + default: + return -IOP_EIO; + } + + return translate_error(err); + } + + virtual int read(void* buf, u32 count) + { + return translate_error(::read(fd, buf, count)); + } + + virtual int write(void* buf, u32 count) + { + return translate_error(::write(fd, buf, count)); } }; - filedesc fds[maxfds]; - - template - T* getfd(int fd) + class HostDir : public IOManDir { - fd -= firstfd; + public: + DIR* dir; + std::string path; - if (fd < 0 || fd >= maxfds) - return NULL; - - return fds[fd]; - } - - template - int allocfd(T *obj) - { - for (int i = 0; i < maxfds; i++) + HostDir(DIR* native_dir, const std::string native_path) { - if (!fds[i]) + dir = native_dir; + path = native_path; + } + + virtual ~HostDir() = default; + + static int open(IOManDir** dir, const std::string& full_path) + { + const std::string relativePath = full_path.substr(full_path.find(':') + 1); + const std::string path = host_path(relativePath); + + DIR* dirent = ::opendir(path.c_str()); + if (!dirent) + return -IOP_ENOENT; // Should return ENOTDIR if path is a file? + + *dir = new HostDir(dirent, relativePath); + if (!*dir) + return -IOP_ENOMEM; + + return 0; + } + + virtual int read(void* buf) + { + fio_dirent_t* hostcontent = (fio_dirent_t*)buf; + struct dirent* dire = ::readdir(dir); + + if (dire == NULL) + return 0; + + strcpy(hostcontent->name, dire->d_name); + host_stat(host_path(path + dire->d_name), &hostcontent->stat); + + return 1; + } + + virtual void close() + { + ::closedir(dir); + delete this; + } + }; + + namespace ioman + { + const int firstfd = 0x100; + const int maxfds = 0x100; + int openfds = 0; + + int freefdcount() + { + return maxfds - openfds; + } + + struct filedesc + { + enum { - fds[i] = obj; - return firstfd + i; + FILE_FREE, + FILE_FILE, + FILE_DIR, + } type; + union + { + IOManFile* file; + IOManDir* dir; + }; + + constexpr filedesc() + : type(FILE_FREE) + , file(nullptr) + { + } + operator bool() const { return type != FILE_FREE; } + operator IOManFile*() const { return type == FILE_FILE ? file : NULL; } + operator IOManDir*() const { return type == FILE_DIR ? dir : NULL; } + void operator=(IOManFile* f) + { + type = FILE_FILE; + file = f; + openfds++; + } + void operator=(IOManDir* d) + { + type = FILE_DIR; + dir = d; + openfds++; + } + + void close() + { + switch (type) + { + case FILE_FILE: + file->close(); + file = NULL; + break; + case FILE_DIR: + dir->close(); + dir = NULL; + break; + case FILE_FREE: + return; + } + + type = FILE_FREE; + openfds--; + } + }; + + filedesc fds[maxfds]; + + template + T* getfd(int fd) + { + fd -= firstfd; + + if (fd < 0 || fd >= maxfds) + return NULL; + + return fds[fd]; + } + + template + int allocfd(T* obj) + { + for (int i = 0; i < maxfds; i++) + { + if (!fds[i]) + { + fds[i] = obj; + return firstfd + i; + } + } + + obj->close(); + return -IOP_EMFILE; + } + + void freefd(int fd) + { + fd -= firstfd; + + if (fd < 0 || fd >= maxfds) + return; + + fds[fd].close(); + } + + void reset() + { + for (int i = 0; i < maxfds; i++) + { + if (fds[i]) + fds[i].close(); } } - obj->close(); - return -IOP_EMFILE; - } - - void freefd(int fd) - { - fd -= firstfd; - - if (fd < 0 || fd >= maxfds) - return; - - fds[fd].close(); - } - - void reset() - { - for (int i = 0; i < maxfds; i++) + bool is_host(const std::string path) { - if (fds[i]) - fds[i].close(); + auto not_number_pos = path.find_first_not_of("0123456789", 4); + if (not_number_pos == std::string::npos) + return false; + + return ((!g_GameStarted || EmuConfig.HostFs) && 0 == path.compare(0, 4, "host") && path[not_number_pos] == ':'); } - } - bool is_host(const std::string path) - { - auto not_number_pos = path.find_first_not_of("0123456789", 4); - if (not_number_pos == std::string::npos) - return false; - - return ((!g_GameStarted || EmuConfig.HostFs) && 0 == path.compare(0, 4, "host") && path[not_number_pos] == ':'); - } - - int open_HLE() - { - IOManFile *file = NULL; - const std::string path = Ra0; - s32 flags = a1; - u16 mode = a2; - - if (is_host(path)) + int open_HLE() { - if (!freefdcount()) + IOManFile* file = NULL; + const std::string path = Ra0; + s32 flags = a1; + u16 mode = a2; + + if (is_host(path)) { - v0 = -IOP_EMFILE; + if (!freefdcount()) + { + v0 = -IOP_EMFILE; + pc = ra; + return 1; + } + + int err = HostFile::open(&file, path, flags, mode); + + if (err != 0 || !file) + { + if (err == 0) // ??? + err = -IOP_EIO; + if (file) // ?????? + file->close(); + v0 = err; + } + else + { + v0 = allocfd(file); + if ((s32)v0 < 0) + file->close(); + } + pc = ra; return 1; } - int err = HostFile::open(&file, path, flags, mode); + return 0; + } - if (err != 0 || !file) + int close_HLE() + { + s32 fd = a0; + + if (getfd(fd)) { - if (err == 0) // ??? + freefd(fd); + v0 = 0; + pc = ra; + return 1; + } + + return 0; + } + + int dopen_HLE() + { + IOManDir* dir = NULL; + const std::string path = Ra0; + + int err = HostDir::open(&dir, path); + + if (err != 0 || !dir) + { + if (err == 0) err = -IOP_EIO; - if (file) // ?????? - file->close(); + if (dir) + dir->close(); v0 = err; } else { - v0 = allocfd(file); + v0 = allocfd(dir); if ((s32)v0 < 0) - file->close(); + dir->close(); } pc = ra; return 1; } - return 0; - } - - int close_HLE() - { - s32 fd = a0; - - if (getfd(fd)) + int dclose_HLE() { - freefd(fd); - v0 = 0; - pc = ra; - return 1; - } + s32 dir = a0; - return 0; - } - - int dopen_HLE() - { - IOManDir *dir = NULL; - const std::string path = Ra0; - - int err = HostDir::open(&dir, path); - - if (err != 0 || !dir) - { - if (err == 0) - err = -IOP_EIO; - if (dir) - dir->close(); - v0 = err; - } - else - { - v0 = allocfd(dir); - if ((s32)v0 < 0) - dir->close(); - } - - pc = ra; - return 1; - } - - int dclose_HLE() - { - s32 dir = a0; - - if (getfd(dir)) - { - freefd(dir); - v0 = 0; - pc = ra; - return 1; - } - - return 0; - } - - int dread_HLE() - { - s32 fh = a0; - u32 data = a1; - - if (IOManDir *dir = getfd(fh)) - { - std::unique_ptr buf(new char[sizeof(fio_dirent_t)]); - v0 = dir->read(buf.get()); - - for (s32 i = 0; i < (s32)sizeof(fio_dirent_t); i++) - iopMemWrite8(data + i, buf[i]); - - pc = ra; - return 1; - } - - return 0; - } - - int getStat_HLE() - { - const std::string path = Ra0; - u32 data = a1; - - if (is_host(path)) - { - const std::string full_path = host_path(path.substr(path.find(':') + 1)); - std::unique_ptr buf(new char[sizeof(fio_stat_t)]); - v0 = host_stat(full_path, (fio_stat_t *)buf.get()); - - for (s32 i = 0; i < (s32)sizeof(fio_stat_t); i++) - iopMemWrite8(data + i, buf[i]); - - pc = ra; - return 1; - } - - return 0; - } - - int lseek_HLE() - { - s32 fd = a0; - s32 offset = a1; - s32 whence = a2; - - if (IOManFile *file = getfd(fd)) - { - v0 = file->lseek(offset, whence); - pc = ra; - return 1; - } - - return 0; - } - - int mkdir_HLE() - { - const std::string full_path = Ra0; - - if (is_host(full_path)) - { - const std::string path = full_path.substr(full_path.find(':') + 1); - int tmpError; -#ifdef _WIN32 - tmpError = ::mkdir(host_path(path).data()); -#else - tmpError = ::mkdir(host_path(path).data(), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); -#endif - v0 = HostFile::translate_error(tmpError); - pc = ra; - return 1; - } - - return 0; - } - - int read_HLE() - { - s32 fd = a0; - u32 data = a1; - u32 count = a2; - - if (IOManFile *file = getfd(fd)) - { - try { - std::unique_ptr buf(new char[count]); - - v0 = file->read(buf.get(), count); - - for (s32 i = 0; i < (s32)v0; i++) - iopMemWrite8(data + i, buf[i]); - } - catch (const std::bad_alloc &) { - v0 = -IOP_ENOMEM; - } - - pc = ra; - return 1; - } - - return 0; - } - - int rmdir_HLE() - { - const std::string full_path = Ra0; - - if (is_host(full_path)) - { - const std::string path = full_path.substr(full_path.find(':') + 1); - v0 = HostFile::translate_error(::rmdir(host_path(path).data())); - pc = ra; - return 1; - } - - return 0; - } - - int write_HLE() - { - s32 fd = a0; - u32 data = a1; - u32 count = a2; - - if (fd == 1) // stdout - { - const std::string s = Ra1; - iopConLog(ShiftJIS_ConvertString(s.data(), a2)); - pc = ra; - v0 = a2; - return 1; - } - else if (IOManFile *file = getfd(fd)) - { - try { - std::unique_ptr buf(new char[count]); - - for (u32 i = 0; i < count; i++) - buf[i] = iopMemRead8(data + i); - - v0 = file->write(buf.get(), count); - } - catch (const std::bad_alloc &) { - v0 = -IOP_ENOMEM; - } - - pc = ra; - return 1; - } - - return 0; - } -} - -namespace sysmem { - int Kprintf_HLE() - { - // Emulate the expected Kprintf functionality: - iopMemWrite32(sp, a0); - iopMemWrite32(sp + 4, a1); - iopMemWrite32(sp + 8, a2); - iopMemWrite32(sp + 12, a3); - pc = ra; - - const std::string fmt = Ra0; - - // From here we're intercepting the Kprintf and piping it to our console, complete with - // printf-style formatting processing. This part can be skipped if the user has the - // console disabled. - - if (!SysConsole.iopConsole.IsActive()) return 1; - - char tmp[1024], tmp2[1024]; - char *ptmp = tmp; - int n=1, i=0, j = 0; - - while (fmt[i]) - { - switch (fmt[i]) + if (getfd(dir)) { - case '%': - j = 0; - tmp2[j++] = '%'; -_start: - switch (fmt[++i]) - { - case '.': - case 'l': - tmp2[j++] = fmt[i]; - goto _start; - default: - if (fmt[i] >= '0' && fmt[i] <= '9') - { + freefd(dir); + v0 = 0; + pc = ra; + return 1; + } + + return 0; + } + + int dread_HLE() + { + s32 fh = a0; + u32 data = a1; + + if (IOManDir* dir = getfd(fh)) + { + std::unique_ptr buf(new char[sizeof(fio_dirent_t)]); + v0 = dir->read(buf.get()); + + for (s32 i = 0; i < (s32)sizeof(fio_dirent_t); i++) + iopMemWrite8(data + i, buf[i]); + + pc = ra; + return 1; + } + + return 0; + } + + int getStat_HLE() + { + const std::string path = Ra0; + u32 data = a1; + + if (is_host(path)) + { + const std::string full_path = host_path(path.substr(path.find(':') + 1)); + std::unique_ptr buf(new char[sizeof(fio_stat_t)]); + v0 = host_stat(full_path, (fio_stat_t*)buf.get()); + + for (s32 i = 0; i < (s32)sizeof(fio_stat_t); i++) + iopMemWrite8(data + i, buf[i]); + + pc = ra; + return 1; + } + + return 0; + } + + int lseek_HLE() + { + s32 fd = a0; + s32 offset = a1; + s32 whence = a2; + + if (IOManFile* file = getfd(fd)) + { + v0 = file->lseek(offset, whence); + pc = ra; + return 1; + } + + return 0; + } + + int mkdir_HLE() + { + const std::string full_path = Ra0; + + if (is_host(full_path)) + { + const std::string path = full_path.substr(full_path.find(':') + 1); + int tmpError; +#ifdef _WIN32 + tmpError = ::mkdir(host_path(path).data()); +#else + tmpError = ::mkdir(host_path(path).data(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); +#endif + v0 = HostFile::translate_error(tmpError); + pc = ra; + return 1; + } + + return 0; + } + + int read_HLE() + { + s32 fd = a0; + u32 data = a1; + u32 count = a2; + + if (IOManFile* file = getfd(fd)) + { + try + { + std::unique_ptr buf(new char[count]); + + v0 = file->read(buf.get(), count); + + for (s32 i = 0; i < (s32)v0; i++) + iopMemWrite8(data + i, buf[i]); + } + catch (const std::bad_alloc&) + { + v0 = -IOP_ENOMEM; + } + + pc = ra; + return 1; + } + + return 0; + } + + int rmdir_HLE() + { + const std::string full_path = Ra0; + + if (is_host(full_path)) + { + const std::string path = full_path.substr(full_path.find(':') + 1); + v0 = HostFile::translate_error(::rmdir(host_path(path).data())); + pc = ra; + return 1; + } + + return 0; + } + + int write_HLE() + { + s32 fd = a0; + u32 data = a1; + u32 count = a2; + + if (fd == 1) // stdout + { + const std::string s = Ra1; + iopConLog(ShiftJIS_ConvertString(s.data(), a2)); + pc = ra; + v0 = a2; + return 1; + } + else if (IOManFile* file = getfd(fd)) + { + try + { + std::unique_ptr buf(new char[count]); + + for (u32 i = 0; i < count; i++) + buf[i] = iopMemRead8(data + i); + + v0 = file->write(buf.get(), count); + } + catch (const std::bad_alloc&) + { + v0 = -IOP_ENOMEM; + } + + pc = ra; + return 1; + } + + return 0; + } + } // namespace ioman + + namespace sysmem + { + int Kprintf_HLE() + { + // Emulate the expected Kprintf functionality: + iopMemWrite32(sp, a0); + iopMemWrite32(sp + 4, a1); + iopMemWrite32(sp + 8, a2); + iopMemWrite32(sp + 12, a3); + pc = ra; + + const std::string fmt = Ra0; + + // From here we're intercepting the Kprintf and piping it to our console, complete with + // printf-style formatting processing. This part can be skipped if the user has the + // console disabled. + + if (!SysConsole.iopConsole.IsActive()) + return 1; + + char tmp[1024], tmp2[1024]; + char* ptmp = tmp; + int n = 1, i = 0, j = 0; + + while (fmt[i]) + { + switch (fmt[i]) + { + case '%': + j = 0; + tmp2[j++] = '%'; + _start: + switch (fmt[++i]) + { + case '.': + case 'l': tmp2[j++] = fmt[i]; goto _start; - } - break; - } + default: + if (fmt[i] >= '0' && fmt[i] <= '9') + { + tmp2[j++] = fmt[i]; + goto _start; + } + break; + } - tmp2[j++] = fmt[i]; - tmp2[j] = 0; + tmp2[j++] = fmt[i]; + tmp2[j] = 0; - switch (fmt[i]) - { - case 'f': case 'F': - ptmp+= sprintf(ptmp, tmp2, (float)iopMemRead32(sp + n * 4)); - n++; - break; + switch (fmt[i]) + { + case 'f': + case 'F': + ptmp += sprintf(ptmp, tmp2, (float)iopMemRead32(sp + n * 4)); + n++; + break; - case 'a': case 'A': - case 'e': case 'E': - case 'g': case 'G': - ptmp+= sprintf(ptmp, tmp2, (double)iopMemRead32(sp + n * 4)); - n++; - break; + case 'a': + case 'A': + case 'e': + case 'E': + case 'g': + case 'G': + ptmp += sprintf(ptmp, tmp2, (double)iopMemRead32(sp + n * 4)); + n++; + break; - case 'p': - case 'i': - case 'd': case 'D': - case 'o': case 'O': - case 'x': case 'X': - ptmp+= sprintf(ptmp, tmp2, (u32)iopMemRead32(sp + n * 4)); - n++; - break; + case 'p': + case 'i': + case 'd': + case 'D': + case 'o': + case 'O': + case 'x': + case 'X': + ptmp += sprintf(ptmp, tmp2, (u32)iopMemRead32(sp + n * 4)); + n++; + break; - case 'c': - ptmp+= sprintf(ptmp, tmp2, (u8)iopMemRead32(sp + n * 4)); - n++; - break; + case 'c': + ptmp += sprintf(ptmp, tmp2, (u8)iopMemRead32(sp + n * 4)); + n++; + break; - case 's': + case 's': { std::string s = iopMemReadString(iopMemRead32(sp + n * 4)); ptmp += sprintf(ptmp, tmp2, s.data()); @@ -760,178 +811,204 @@ _start: } break; - case '%': - *ptmp++ = fmt[i]; - break; + case '%': + *ptmp++ = fmt[i]; + break; - default: - break; - } - i++; - break; + default: + break; + } + i++; + break; - default: - *ptmp++ = fmt[i++]; - break; + default: + *ptmp++ = fmt[i++]; + break; + } } + *ptmp = 0; + iopConLog(ShiftJIS_ConvertString(tmp, 1023)); + + return 1; } - *ptmp = 0; - iopConLog( ShiftJIS_ConvertString(tmp, 1023) ); + } // namespace sysmem - return 1; - } -} - -namespace loadcore { - void RegisterLibraryEntries_DEBUG() + namespace loadcore { - const std::string modname = iopMemReadString(a0 + 12); - DevCon.WriteLn(Color_Gray, "RegisterLibraryEntries: %8.8s version %x.%02x", modname.data(), (unsigned)iopMemRead8(a0 + 9), (unsigned)iopMemRead8(a0 + 8)); - } -} + void RegisterLibraryEntries_DEBUG() + { + const std::string modname = iopMemReadString(a0 + 12); + DevCon.WriteLn(Color_Gray, "RegisterLibraryEntries: %8.8s version %x.%02x", modname.data(), (unsigned)iopMemRead8(a0 + 9), (unsigned)iopMemRead8(a0 + 8)); + } + } // namespace loadcore -namespace intrman { - static const char* intrname[] = { - "INT_VBLANK", "INT_GM", "INT_CDROM", "INT_DMA", //00 - "INT_RTC0", "INT_RTC1", "INT_RTC2", "INT_SIO0", //04 - "INT_SIO1", "INT_SPU", "INT_PIO", "INT_EVBLANK", //08 - "INT_DVD", "INT_PCMCIA", "INT_RTC3", "INT_RTC4", //0C - "INT_RTC5", "INT_SIO2", "INT_HTR0", "INT_HTR1", //10 - "INT_HTR2", "INT_HTR3", "INT_USB", "INT_EXTR", //14 - "INT_FWRE", "INT_FDMA", "INT_1A", "INT_1B", //18 - "INT_1C", "INT_1D", "INT_1E", "INT_1F", //1C - "INT_dmaMDECi", "INT_dmaMDECo", "INT_dmaGPU", "INT_dmaCD", //20 - "INT_dmaSPU", "INT_dmaPIO", "INT_dmaOTC", "INT_dmaBERR", //24 - "INT_dmaSPU2", "INT_dma8", "INT_dmaSIF0", "INT_dmaSIF1", //28 - "INT_dmaSIO2i", "INT_dmaSIO2o", "INT_2E", "INT_2F", //2C - "INT_30", "INT_31", "INT_32", "INT_33", //30 - "INT_34", "INT_35", "INT_36", "INT_37", //34 - "INT_38", "INT_39", "INT_3A", "INT_3B", //38 - "INT_3C", "INT_3D", "INT_3E", "INT_3F", //3C - "INT_MAX" //40 - }; - - void RegisterIntrHandler_DEBUG() + namespace intrman { - DevCon.WriteLn(Color_Gray, "RegisterIntrHandler: intr %s, handler %x", intrname[a0], a2); - } -} + // clang-format off + static const char* intrname[] = { + "INT_VBLANK", "INT_GM", "INT_CDROM", "INT_DMA", //00 + "INT_RTC0", "INT_RTC1", "INT_RTC2", "INT_SIO0", //04 + "INT_SIO1", "INT_SPU", "INT_PIO", "INT_EVBLANK", //08 + "INT_DVD", "INT_PCMCIA", "INT_RTC3", "INT_RTC4", //0C + "INT_RTC5", "INT_SIO2", "INT_HTR0", "INT_HTR1", //10 + "INT_HTR2", "INT_HTR3", "INT_USB", "INT_EXTR", //14 + "INT_FWRE", "INT_FDMA", "INT_1A", "INT_1B", //18 + "INT_1C", "INT_1D", "INT_1E", "INT_1F", //1C + "INT_dmaMDECi", "INT_dmaMDECo", "INT_dmaGPU", "INT_dmaCD", //20 + "INT_dmaSPU", "INT_dmaPIO", "INT_dmaOTC", "INT_dmaBERR", //24 + "INT_dmaSPU2", "INT_dma8", "INT_dmaSIF0", "INT_dmaSIF1", //28 + "INT_dmaSIO2i", "INT_dmaSIO2o", "INT_2E", "INT_2F", //2C + "INT_30", "INT_31", "INT_32", "INT_33", //30 + "INT_34", "INT_35", "INT_36", "INT_37", //34 + "INT_38", "INT_39", "INT_3A", "INT_3B", //38 + "INT_3C", "INT_3D", "INT_3E", "INT_3F", //3C + "INT_MAX" //40 + }; + // clang-format on -namespace sifcmd { - void sceSifRegisterRpc_DEBUG() + void RegisterIntrHandler_DEBUG() + { + DevCon.WriteLn(Color_Gray, "RegisterIntrHandler: intr %s, handler %x", intrname[a0], a2); + } + } // namespace intrman + + namespace sifcmd { - DevCon.WriteLn( Color_Gray, "sifcmd sceSifRegisterRpc: rpc_id %x", a1); - } -} + void sceSifRegisterRpc_DEBUG() + { + DevCon.WriteLn(Color_Gray, "sifcmd sceSifRegisterRpc: rpc_id %x", a1); + } + } // namespace sifcmd -u32 irxImportTableAddr(u32 entrypc) -{ - u32 i; + u32 irxImportTableAddr(u32 entrypc) + { + u32 i; - i = entrypc - 0x18; - while (entrypc - i < 0x2000) { - if (iopMemRead32(i) == 0x41e00000) - return i; - i -= 4; + i = entrypc - 0x18; + while (entrypc - i < 0x2000) + { + if (iopMemRead32(i) == 0x41e00000) + return i; + i -= 4; + } + + return 0; } - return 0; -} + const char* irxImportFuncname(const std::string& libname, u16 index) + { +#include "IopModuleNames.cpp" -const char* irxImportFuncname(const std::string &libname, u16 index) -{ - #include "IopModuleNames.cpp" + switch (index) + { + case 0: + return "start"; + // case 1: reinit? + case 2: + return "shutdown"; + // case 3: ??? + } - switch (index) { - case 0: return "start"; - // case 1: reinit? - case 2: return "shutdown"; - // case 3: ??? + return 0; } - return 0; -} +// clang-format off +#define MODULE(n) \ + if (#n == libname) \ + { \ + using namespace n; \ + switch (index) \ + { +#define END_MODULE \ + } \ + } +#define EXPORT_D(i, n) \ + case (i): \ + return n##_DEBUG; +#define EXPORT_H(i, n) \ + case (i): \ + return n##_HLE; + // clang-format on -#define MODULE(n) if (#n == libname) { using namespace n; switch (index) { -#define END_MODULE }} -#define EXPORT_D(i, n) case (i): return n ## _DEBUG; -#define EXPORT_H(i, n) case (i): return n ## _HLE; + irxHLE irxImportHLE(const std::string& libname, u16 index) + { + // debugging output + // clang-format off + MODULE(sysmem) + EXPORT_H( 14, Kprintf) + END_MODULE + + MODULE(ioman) + EXPORT_H( 4, open) + EXPORT_H( 5, close) + EXPORT_H( 6, read) + EXPORT_H( 7, write) + EXPORT_H( 8, lseek) + EXPORT_H( 11, mkdir) + EXPORT_H( 12, rmdir) + EXPORT_H( 13, dopen) + EXPORT_H( 14, dclose) + EXPORT_H( 15, dread) + EXPORT_H( 16, getStat) + END_MODULE + // clang-format on -irxHLE irxImportHLE(const std::string &libname, u16 index) -{ - // debugging output - MODULE(sysmem) - EXPORT_H( 14, Kprintf) - END_MODULE + return 0; + } - MODULE(ioman) - EXPORT_H( 4, open) - EXPORT_H( 5, close) - EXPORT_H( 6, read) - EXPORT_H( 7, write) - EXPORT_H( 8, lseek) - EXPORT_H( 11, mkdir) - EXPORT_H( 12, rmdir) - EXPORT_H( 13, dopen) - EXPORT_H( 14, dclose) - EXPORT_H( 15, dread) - EXPORT_H( 16, getStat) - END_MODULE + irxDEBUG irxImportDebug(const std::string& libname, u16 index) + { + // clang-format off + MODULE(loadcore) + EXPORT_D( 6, RegisterLibraryEntries) + END_MODULE + MODULE(intrman) + EXPORT_D( 4, RegisterIntrHandler) + END_MODULE + MODULE(sifcmd) + EXPORT_D( 17, sceSifRegisterRpc) + END_MODULE + // clang-format off - return 0; -} - -irxDEBUG irxImportDebug(const std::string &libname, u16 index) -{ - MODULE(loadcore) - EXPORT_D( 6, RegisterLibraryEntries) - END_MODULE - MODULE(intrman) - EXPORT_D( 4, RegisterIntrHandler) - END_MODULE - MODULE(sifcmd) - EXPORT_D( 17, sceSifRegisterRpc) - END_MODULE - - return 0; -} + return 0; + } #undef MODULE #undef END_MODULE #undef EXPORT_D #undef EXPORT_H -void irxImportLog(const std::string &libname, u16 index, const char *funcname) -{ - PSXBIOS_LOG("%8.8s.%03d: %s (%x, %x, %x, %x)", - libname.data(), index, funcname ? funcname : "unknown", - a0, a1, a2, a3); -} + void irxImportLog(const std::string& libname, u16 index, const char* funcname) + { + PSXBIOS_LOG("%8.8s.%03d: %s (%x, %x, %x, %x)", + libname.data(), index, funcname ? funcname : "unknown", + a0, a1, a2, a3); + } -void __fastcall irxImportLog_rec(u32 import_table, u16 index, const char *funcname) -{ - irxImportLog(iopMemReadString(import_table + 12, 8), index, funcname); -} + void __fastcall irxImportLog_rec(u32 import_table, u16 index, const char* funcname) + { + irxImportLog(iopMemReadString(import_table + 12, 8), index, funcname); + } -int irxImportExec(u32 import_table, u16 index) -{ - if (!import_table) - return 0; + int irxImportExec(u32 import_table, u16 index) + { + if (!import_table) + return 0; - std::string libname = iopMemReadString(import_table + 12, 8); - const char *funcname = irxImportFuncname(libname, index); - irxHLE hle = irxImportHLE(libname, index); - irxDEBUG debug = irxImportDebug(libname, index); + std::string libname = iopMemReadString(import_table + 12, 8); + const char* funcname = irxImportFuncname(libname, index); + irxHLE hle = irxImportHLE(libname, index); + irxDEBUG debug = irxImportDebug(libname, index); - irxImportLog(libname, index, funcname); + irxImportLog(libname, index, funcname); - if (debug) - debug(); - - if (hle) - return hle(); - else - return 0; -} + if (debug) + debug(); -} // end namespace R3000A + if (hle) + return hle(); + else + return 0; + } + +} // end namespace R3000A diff --git a/pcsx2/IopBios.h b/pcsx2/IopBios.h index 1e37e4e478..e3be4049df 100644 --- a/pcsx2/IopBios.h +++ b/pcsx2/IopBios.h @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team + * Copyright (C) 2002-2021 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -16,30 +16,31 @@ #ifndef __PSXBIOS_H__ #define __PSXBIOS_H__ -#define IOP_ENOENT 2 -#define IOP_EIO 5 -#define IOP_ENOMEM 12 -#define IOP_EACCES 13 -#define IOP_ENODEV 19 -#define IOP_EISDIR 21 -#define IOP_EMFILE 24 -#define IOP_EROFS 30 +#define IOP_ENOENT 2 +#define IOP_EIO 5 +#define IOP_ENOMEM 12 +#define IOP_EACCES 13 +#define IOP_ENODEV 19 +#define IOP_EISDIR 21 +#define IOP_EMFILE 24 +#define IOP_EROFS 30 -#define IOP_O_RDONLY 0x001 -#define IOP_O_WRONLY 0x002 -#define IOP_O_RDWR 0x003 -#define IOP_O_APPEND 0x100 -#define IOP_O_CREAT 0x200 -#define IOP_O_TRUNC 0x400 -#define IOP_O_EXCL 0x800 +#define IOP_O_RDONLY 0x001 +#define IOP_O_WRONLY 0x002 +#define IOP_O_RDWR 0x003 +#define IOP_O_APPEND 0x100 +#define IOP_O_CREAT 0x200 +#define IOP_O_TRUNC 0x400 +#define IOP_O_EXCL 0x800 #define IOP_SEEK_SET 0 #define IOP_SEEK_CUR 1 #define IOP_SEEK_END 2 -class IOManFile { +class IOManFile +{ public: - static int open(IOManFile **file, const std::string &path, s32 flags, u16 mode) + static int open(IOManFile** file, const std::string& path, s32 flags, u16 mode) { return -IOP_ENODEV; } @@ -47,22 +48,23 @@ public: virtual void close() = 0; virtual int lseek(s32 offset, s32 whence) { return -IOP_EIO; } - virtual int read(void *buf, u32 count) { return -IOP_EIO; } - virtual int write(void *buf, u32 count) { return -IOP_EIO; } + virtual int read(void* buf, u32 count) { return -IOP_EIO; } + virtual int write(void* buf, u32 count) { return -IOP_EIO; } }; -class IOManDir { +class IOManDir +{ // Don't think about it until we know the loaded ioman version. // The dirent structure changed between versions. public: - static int open(IOManDir **dir, const std::string &full_path) - { - return -IOP_ENODEV; - } - + static int open(IOManDir** dir, const std::string& full_path) + { + return -IOP_ENODEV; + } + virtual void close() = 0; - - virtual int read(void *buf) { return -IOP_EIO; } + + virtual int read(void* buf) { return -IOP_EIO; } }; typedef int (*irxHLE)(); // return 1 if handled, otherwise 0 @@ -71,18 +73,18 @@ typedef void (*irxDEBUG)(); namespace R3000A { u32 irxImportTableAddr(u32 entrypc); - const char* irxImportFuncname(const std::string &libname, u16 index); - irxHLE irxImportHLE(const std::string &libnam, u16 index); - irxDEBUG irxImportDebug(const std::string & libname, u16 index); - void irxImportLog(const std::string &libnameptr, u16 index, const char *funcname); - void __fastcall irxImportLog_rec(u32 import_table, u16 index, const char *funcname); + const char* irxImportFuncname(const std::string& libname, u16 index); + irxHLE irxImportHLE(const std::string& libnam, u16 index); + irxDEBUG irxImportDebug(const std::string& libname, u16 index); + void irxImportLog(const std::string& libnameptr, u16 index, const char* funcname); + void __fastcall irxImportLog_rec(u32 import_table, u16 index, const char* funcname); int irxImportExec(u32 import_table, u16 index); namespace ioman { void reset(); } -} +} // namespace R3000A extern void Hle_SetElfPath(const char* elfFileName);