mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-02-08 00:35:42 +01:00
[rpcsx-os] Use orbis::File instead of IoDeviceInstance
This commit is contained in:
parent
c29aada46a
commit
84b2419241
|
|
@ -4,6 +4,7 @@
|
|||
#include <deque>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
|
@ -46,7 +47,9 @@ using kunmap =
|
|||
std::unordered_map<K, T, Hash, Pred, kallocator<std::pair<const K, T>>>;
|
||||
} // namespace utils
|
||||
|
||||
template <typename T, typename... Args> T *knew(Args &&...args) {
|
||||
template <typename T, typename... Args>
|
||||
requires(std::is_constructible_v<T, Args...>)
|
||||
T *knew(Args &&...args) {
|
||||
auto loc = static_cast<T *>(utils::kalloc(sizeof(T), alignof(T)));
|
||||
auto res = std::construct_at(loc, std::forward<Args>(args)...);
|
||||
if constexpr (requires(T *t) { t->_total_size = sizeof(T); })
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "KernelAllocator.hpp"
|
||||
#include "error/ErrorCode.hpp"
|
||||
#include <atomic>
|
||||
#include "utils/Rc.hpp"
|
||||
#include "utils/SharedMutex.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace orbis {
|
||||
|
|
@ -16,10 +16,8 @@ struct FileOps {
|
|||
std::int32_t flags;
|
||||
ErrorCode (*ioctl)(File *file, std::uint64_t request, void *argp,
|
||||
Thread *thread) = nullptr;
|
||||
ErrorCode (*rdwr)(File *file, Uio *uio, Thread *thread) = nullptr;
|
||||
ErrorCode (*close)(File *file, Thread *thread) = nullptr;
|
||||
ErrorCode (*lseek)(File *file, std::uint64_t *offset, std::uint32_t whence,
|
||||
Thread *thread) = nullptr;
|
||||
ErrorCode (*read)(File *file, Uio *uio, Thread *thread) = nullptr;
|
||||
ErrorCode (*write)(File *file, Uio *uio, Thread *thread) = nullptr;
|
||||
|
||||
ErrorCode (*truncate)(File *file, std::uint64_t len,
|
||||
Thread *thread) = nullptr;
|
||||
|
|
@ -40,17 +38,10 @@ struct FileOps {
|
|||
Thread *thread) = nullptr;
|
||||
};
|
||||
|
||||
struct File final {
|
||||
FileOps *ops;
|
||||
struct File : RcBase {
|
||||
shared_mutex mtx;
|
||||
const FileOps *ops = nullptr;
|
||||
Ref<RcBase> device;
|
||||
std::atomic<unsigned> refs{0};
|
||||
|
||||
void incRef() { refs.fetch_add(1, std::memory_order::acquire); }
|
||||
|
||||
void decRef() {
|
||||
if (refs.fetch_sub(1, std::memory_order::release) == 1) {
|
||||
kdelete(this);
|
||||
}
|
||||
}
|
||||
std::uint64_t nextOff = 0;
|
||||
};
|
||||
} // namespace orbis
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ struct KEvent;
|
|||
struct timespec;
|
||||
struct Stat;
|
||||
struct stack_t;
|
||||
struct IoVec;
|
||||
|
||||
SysResult nosys(Thread *thread);
|
||||
|
||||
|
|
@ -126,10 +127,8 @@ SysResult sys_gettimeofday(Thread *thread, ptr<orbis::timeval> tp,
|
|||
SysResult sys_getrusage(Thread *thread, sint who, ptr<struct rusage> rusage);
|
||||
SysResult sys_getsockopt(Thread *thread, sint s, sint level, sint name,
|
||||
caddr_t val, ptr<sint> avalsize);
|
||||
SysResult sys_readv(Thread *thread, sint fd, ptr<struct iovec> iovp,
|
||||
uint iovcnt);
|
||||
SysResult sys_writev(Thread *thread, sint fd, ptr<struct iovec> iovp,
|
||||
uint iovcnt);
|
||||
SysResult sys_readv(Thread *thread, sint fd, ptr<IoVec> iovp, uint iovcnt);
|
||||
SysResult sys_writev(Thread *thread, sint fd, ptr<IoVec> iovp, uint iovcnt);
|
||||
SysResult sys_settimeofday(Thread *thread, ptr<struct timeval> tp,
|
||||
ptr<orbis::timezone> tzp);
|
||||
SysResult sys_fchown(Thread *thread, sint fd, sint uid, sint gid);
|
||||
|
|
@ -249,10 +248,10 @@ SysResult sys_lutimes(Thread *thread, ptr<char> path, ptr<struct timeval> tptr);
|
|||
SysResult sys_nstat(Thread *thread, ptr<char> path, ptr<struct nstat> ub);
|
||||
SysResult sys_nfstat(Thread *thread, sint fd, ptr<struct nstat> sb);
|
||||
SysResult sys_nlstat(Thread *thread, ptr<char> path, ptr<struct nstat> ub);
|
||||
SysResult sys_preadv(Thread *thread, sint fd, ptr<struct iovec> iovp,
|
||||
uint iovcnt, off_t offset);
|
||||
SysResult sys_pwritev(Thread *thread, sint fd, ptr<struct iovec> iovp,
|
||||
uint iovcnt, off_t offset);
|
||||
SysResult sys_preadv(Thread *thread, sint fd, ptr<IoVec> iovp, uint iovcnt,
|
||||
off_t offset);
|
||||
SysResult sys_pwritev(Thread *thread, sint fd, ptr<IoVec> iovp, uint iovcnt,
|
||||
off_t offset);
|
||||
SysResult sys_fhopen(Thread *thread, ptr<const struct fhandle> u_fhp,
|
||||
sint flags);
|
||||
SysResult sys_fhstat(Thread *thread, ptr<const struct fhandle> u_fhp,
|
||||
|
|
@ -361,8 +360,7 @@ SysResult sys_eaccess(Thread *thread, ptr<char> path, sint flags);
|
|||
SysResult sys_afs3_syscall(Thread *thread, slong syscall, slong param1,
|
||||
slong param2, slong param3, slong param4,
|
||||
slong param5, slong param6);
|
||||
SysResult sys_nmount(Thread *thread, ptr<struct iovec> iovp, uint iovcnt,
|
||||
sint flags);
|
||||
SysResult sys_nmount(Thread *thread, ptr<IoVec> iovp, uint iovcnt, sint flags);
|
||||
SysResult sys___mac_get_proc(Thread *thread, ptr<struct mac> mac_p);
|
||||
SysResult sys___mac_set_proc(Thread *thread, ptr<struct mac> mac_p);
|
||||
SysResult sys___mac_get_fd(Thread *thread, sint fd, ptr<struct mac> mac_p);
|
||||
|
|
@ -494,14 +492,14 @@ SysResult sys_sctp_generic_sendmsg(Thread *thread, sint sd, caddr_t msg,
|
|||
sint mlen, caddr_t to, __socklen_t tolen,
|
||||
ptr<struct sctp_sndrcvinfo> sinfo,
|
||||
sint flags);
|
||||
SysResult sys_sctp_generic_sendmsg_iov(Thread *thread, sint sd,
|
||||
ptr<struct iovec> iov, sint iovlen,
|
||||
caddr_t to, __socklen_t tolen,
|
||||
SysResult sys_sctp_generic_sendmsg_iov(Thread *thread, sint sd, ptr<IoVec> iov,
|
||||
sint iovlen, caddr_t to,
|
||||
__socklen_t tolen,
|
||||
ptr<struct sctp_sndrcvinfo> sinfo,
|
||||
sint flags);
|
||||
SysResult sys_sctp_generic_recvmsg(Thread *thread, sint sd,
|
||||
ptr<struct iovec> iov, sint iovlen,
|
||||
caddr_t from, __socklen_t fromlen,
|
||||
SysResult sys_sctp_generic_recvmsg(Thread *thread, sint sd, ptr<IoVec> iov,
|
||||
sint iovlen, caddr_t from,
|
||||
__socklen_t fromlen,
|
||||
ptr<struct sctp_sndrcvinfo> sinfo,
|
||||
sint flags);
|
||||
SysResult sys_pread(Thread *thread, sint fd, ptr<void> buf, size_t nbyte,
|
||||
|
|
@ -557,9 +555,9 @@ SysResult sys_symlinkat(Thread *thread, ptr<char> path1, sint fd,
|
|||
SysResult sys_unlinkat(Thread *thread, sint fd, ptr<char> path, sint flag);
|
||||
SysResult sys_posix_openpt(Thread *thread, sint flags);
|
||||
SysResult sys_gssd_syscall(Thread *thread, ptr<char> path);
|
||||
SysResult sys_jail_get(Thread *thread, ptr<struct iovec> iovp, uint iovcnt,
|
||||
SysResult sys_jail_get(Thread *thread, ptr<IoVec> iovp, uint iovcnt,
|
||||
sint flags);
|
||||
SysResult sys_jail_set(Thread *thread, ptr<struct iovec> iovp, uint iovcnt,
|
||||
SysResult sys_jail_set(Thread *thread, ptr<IoVec> iovp, uint iovcnt,
|
||||
sint flags);
|
||||
SysResult sys_jail_remove(Thread *thread, sint jid);
|
||||
SysResult sys_closefrom(Thread *thread, sint lowfd);
|
||||
|
|
|
|||
|
|
@ -6,12 +6,11 @@
|
|||
#include "../thread/Thread.hpp"
|
||||
#include "../thread/types.hpp"
|
||||
#include "ProcessState.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/module/Module.hpp"
|
||||
#include "orbis/utils/IdMap.hpp"
|
||||
#include "orbis/utils/SharedMutex.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace orbis {
|
||||
class KernelContext;
|
||||
struct Thread;
|
||||
|
|
@ -61,7 +60,7 @@ struct Process final {
|
|||
utils::RcIdMap<Semaphore, sint, 4097, 1> semMap;
|
||||
utils::RcIdMap<Module, ModuleHandle> modulesMap;
|
||||
utils::OwningIdMap<Thread, lwpid_t> threadsMap;
|
||||
utils::RcIdMap<utils::RcBase, sint> fileDescriptors;
|
||||
utils::RcIdMap<orbis::File, sint> fileDescriptors;
|
||||
|
||||
// Named objects for debugging
|
||||
utils::shared_mutex namedObjMutex;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@
|
|||
#include "../module/ModuleHandle.hpp"
|
||||
#include "../thread/types.hpp"
|
||||
#include "orbis-config.hpp"
|
||||
#include "orbis/utils/Rc.hpp"
|
||||
|
||||
namespace orbis {
|
||||
struct Thread;
|
||||
struct Module;
|
||||
struct timespec;
|
||||
struct File;
|
||||
|
||||
struct ProcessOps {
|
||||
SysResult (*mmap)(Thread *thread, caddr_t addr, size_t len, sint prot,
|
||||
|
|
@ -28,22 +30,10 @@ struct ProcessOps {
|
|||
SysResult (*virtual_query)(Thread *thread, ptr<const void> addr, sint flags,
|
||||
ptr<void> info, ulong infoSize);
|
||||
|
||||
SysResult (*open)(Thread *thread, ptr<const char> path, sint flags,
|
||||
sint mode);
|
||||
SysResult (*open)(Thread *thread, ptr<const char> path, sint flags, sint mode,
|
||||
Ref<File> *file);
|
||||
SysResult (*socket)(Thread *thread, ptr<const char> name, sint domain,
|
||||
sint type, sint protocol);
|
||||
SysResult (*close)(Thread *thread, sint fd);
|
||||
SysResult (*ioctl)(Thread *thread, sint fd, ulong com, caddr_t argp);
|
||||
SysResult (*write)(Thread *thread, sint fd, ptr<const void> data, ulong size);
|
||||
SysResult (*read)(Thread *thread, sint fd, ptr<void> data, ulong size);
|
||||
SysResult (*pread)(Thread *thread, sint fd, ptr<void> data, ulong size,
|
||||
ulong offset);
|
||||
SysResult (*pwrite)(Thread *thread, sint fd, ptr<const void> data, ulong size,
|
||||
ulong offset);
|
||||
SysResult (*lseek)(Thread *thread, sint fd, ulong offset, sint whence);
|
||||
SysResult (*ftruncate)(Thread *thread, sint fd, off_t length);
|
||||
SysResult (*truncate)(Thread *thread, ptr<const char> path, off_t length);
|
||||
|
||||
sint type, sint protocol, Ref<File> *file);
|
||||
SysResult (*dynlib_get_obj_member)(Thread *thread, ModuleHandle handle,
|
||||
uint64_t index, ptr<ptr<void>> addrp);
|
||||
SysResult (*dynlib_dlsym)(Thread *thread, ModuleHandle handle,
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ enum class UioSeg : std::uint8_t {
|
|||
struct Uio {
|
||||
std::uint64_t offset;
|
||||
IoVec *iov;
|
||||
std::int32_t iovcnt;
|
||||
std::int32_t resid;
|
||||
std::uint32_t iovcnt;
|
||||
std::int64_t resid;
|
||||
UioSeg segflg;
|
||||
UioRw rw;
|
||||
void *td;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
#include <atomic>
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
||||
namespace orbis {
|
||||
|
|
|
|||
|
|
@ -17,53 +17,43 @@ orbis::SysResult orbis::sys_fcntl(Thread *thread, sint fd, sint cmd,
|
|||
}
|
||||
orbis::SysResult orbis::sys_close(Thread *thread, sint fd) {
|
||||
ORBIS_LOG_NOTICE(__FUNCTION__, fd);
|
||||
if (auto close = thread->tproc->ops->close) {
|
||||
return close(thread, fd);
|
||||
if (fd == 0) {
|
||||
return {}; // FIXME: remove when shm would be implemented
|
||||
}
|
||||
|
||||
return ErrorCode::NOSYS;
|
||||
if (thread->tproc->fileDescriptors.close(fd)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
orbis::SysResult orbis::sys_closefrom(Thread *thread, sint lowfd) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_fstat(Thread *thread, sint fd, ptr<Stat> ub) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, fd, ub);
|
||||
thread->where();
|
||||
if (fd == 0) {
|
||||
return ErrorCode::PERM;
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto result = sys_lseek(thread, fd, 0, SEEK_CUR);
|
||||
auto oldpos = thread->retval[0];
|
||||
if (result.isError()) {
|
||||
auto stat = file->ops->stat;
|
||||
if (stat == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
Stat _ub;
|
||||
auto result = uread(_ub, ub);
|
||||
if (result != ErrorCode{}) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = sys_lseek(thread, fd, 0, SEEK_END);
|
||||
auto len = thread->retval[0];
|
||||
if (result.isError()) {
|
||||
result = stat(file.get(), &_ub, thread);
|
||||
if (result != ErrorCode{}) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = sys_read(thread, fd, ub, 1);
|
||||
if (result.isError()) {
|
||||
*ub = {};
|
||||
ub->mode = 0777 | 0x4000;
|
||||
} else {
|
||||
*ub = {};
|
||||
ub->size = len;
|
||||
ub->blksize = 1;
|
||||
ub->blocks = len;
|
||||
ub->mode = 0777 | 0x8000;
|
||||
}
|
||||
|
||||
result = sys_lseek(thread, fd, oldpos, SEEK_SET);
|
||||
if (result.isError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
thread->retval[0] = 0;
|
||||
return {};
|
||||
return uwrite(ub, _ub);
|
||||
}
|
||||
orbis::SysResult orbis::sys_nfstat(Thread *thread, sint fd,
|
||||
ptr<struct nstat> sb) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "thread/Process.hpp"
|
||||
#include "utils/Logs.hpp"
|
||||
|
||||
struct KQueue : orbis::RcBase {};
|
||||
struct KQueue : orbis::File {};
|
||||
|
||||
orbis::SysResult orbis::sys_kqueue(Thread *thread) {
|
||||
ORBIS_LOG_TODO(__FUNCTION__);
|
||||
|
|
|
|||
|
|
@ -1,74 +1,296 @@
|
|||
#include "orbis/utils/Logs.hpp"
|
||||
#include "sys/sysproto.hpp"
|
||||
#include "uio.hpp"
|
||||
|
||||
orbis::SysResult orbis::sys_read(Thread *thread, sint fd, ptr<void> buf,
|
||||
size_t nbyte) {
|
||||
ORBIS_LOG_TRACE(__FUNCTION__, fd, buf, nbyte);
|
||||
if (auto read = thread->tproc->ops->read) {
|
||||
return read(thread, fd, buf, nbyte);
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
return ErrorCode::NOSYS;
|
||||
auto read = file->ops->read;
|
||||
if (read == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
IoVec vec{.base = (void *)buf, .len = nbyte};
|
||||
|
||||
Uio io{
|
||||
.offset = file->nextOff,
|
||||
.iov = &vec,
|
||||
.iovcnt = 1,
|
||||
.segflg = UioSeg::UserSpace,
|
||||
.rw = UioRw::Read,
|
||||
.td = thread,
|
||||
};
|
||||
|
||||
auto error = read(file.get(), &io, thread);
|
||||
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
|
||||
return error;
|
||||
}
|
||||
|
||||
auto cnt = io.offset - file->nextOff;
|
||||
file->nextOff = io.offset;
|
||||
|
||||
thread->retval[0] = cnt;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_pread(Thread *thread, sint fd, ptr<void> buf,
|
||||
size_t nbyte, off_t offset) {
|
||||
ORBIS_LOG_TRACE(__FUNCTION__, fd, buf, nbyte, offset);
|
||||
if (auto pread = thread->tproc->ops->pread) {
|
||||
return pread(thread, fd, buf, nbyte, offset);
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
return ErrorCode::NOSYS;
|
||||
auto read = file->ops->read;
|
||||
if (read == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
IoVec vec{.base = (void *)buf, .len = nbyte};
|
||||
|
||||
Uio io{
|
||||
.offset = static_cast<std::uint64_t>(offset),
|
||||
.iov = &vec,
|
||||
.iovcnt = 1,
|
||||
.segflg = UioSeg::UserSpace,
|
||||
.rw = UioRw::Read,
|
||||
.td = thread,
|
||||
};
|
||||
|
||||
auto error = read(file.get(), &io, thread);
|
||||
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
|
||||
return error;
|
||||
}
|
||||
|
||||
thread->retval[0] = io.offset - offset;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_freebsd6_pread(Thread *thread, sint fd,
|
||||
ptr<void> buf, size_t nbyte, sint,
|
||||
off_t offset) {
|
||||
return sys_pread(thread, fd, buf, nbyte, offset);
|
||||
}
|
||||
orbis::SysResult orbis::sys_readv(Thread *thread, sint fd,
|
||||
ptr<struct iovec> iovp, uint iovcnt) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_readv(Thread *thread, sint fd, ptr<IoVec> iovp,
|
||||
uint iovcnt) {
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto read = file->ops->read;
|
||||
if (read == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
|
||||
Uio io{
|
||||
.offset = file->nextOff,
|
||||
.iov = iovp,
|
||||
.iovcnt = iovcnt,
|
||||
.segflg = UioSeg::UserSpace,
|
||||
.rw = UioRw::Read,
|
||||
.td = thread,
|
||||
};
|
||||
|
||||
auto error = read(file.get(), &io, thread);
|
||||
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
|
||||
return error;
|
||||
}
|
||||
|
||||
auto cnt = io.offset - file->nextOff;
|
||||
file->nextOff = io.offset;
|
||||
thread->retval[0] = cnt;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_preadv(Thread *thread, sint fd,
|
||||
ptr<struct iovec> iovp, uint iovcnt,
|
||||
off_t offset) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_preadv(Thread *thread, sint fd, ptr<IoVec> iovp,
|
||||
uint iovcnt, off_t offset) {
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto read = file->ops->read;
|
||||
if (read == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
|
||||
Uio io{
|
||||
.offset = static_cast<std::uint64_t>(offset),
|
||||
.iov = iovp,
|
||||
.iovcnt = iovcnt,
|
||||
.segflg = UioSeg::UserSpace,
|
||||
.rw = UioRw::Read,
|
||||
.td = thread,
|
||||
};
|
||||
|
||||
auto error = read(file.get(), &io, thread);
|
||||
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
|
||||
return error;
|
||||
}
|
||||
|
||||
thread->retval[0] = io.offset - offset;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_write(Thread *thread, sint fd, ptr<const void> buf,
|
||||
size_t nbyte) {
|
||||
ORBIS_LOG_NOTICE(__FUNCTION__, fd, buf, nbyte);
|
||||
if (auto write = thread->tproc->ops->write) {
|
||||
return write(thread, fd, buf, nbyte);
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
return ErrorCode::NOSYS;
|
||||
auto write = file->ops->write;
|
||||
if (write == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
IoVec vec{.base = (void *)buf, .len = nbyte};
|
||||
|
||||
Uio io{
|
||||
.offset = file->nextOff,
|
||||
.iov = &vec,
|
||||
.iovcnt = 1,
|
||||
.segflg = UioSeg::UserSpace,
|
||||
.rw = UioRw::Write,
|
||||
.td = thread,
|
||||
};
|
||||
|
||||
auto error = write(file.get(), &io, thread);
|
||||
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
|
||||
return error;
|
||||
}
|
||||
|
||||
auto cnt = io.offset - file->nextOff;
|
||||
file->nextOff = io.offset;
|
||||
|
||||
thread->retval[0] = cnt;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_pwrite(Thread *thread, sint fd, ptr<const void> buf,
|
||||
size_t nbyte, off_t offset) {
|
||||
if (auto pwrite = thread->tproc->ops->pwrite) {
|
||||
return pwrite(thread, fd, buf, nbyte, offset);
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
return ErrorCode::NOSYS;
|
||||
|
||||
auto write = file->ops->write;
|
||||
if (write == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
IoVec vec{.base = (void *)buf, .len = nbyte};
|
||||
|
||||
Uio io{
|
||||
.offset = static_cast<std::uint64_t>(offset),
|
||||
.iov = &vec,
|
||||
.iovcnt = 1,
|
||||
.segflg = UioSeg::UserSpace,
|
||||
.rw = UioRw::Write,
|
||||
.td = thread,
|
||||
};
|
||||
|
||||
auto error = write(file.get(), &io, thread);
|
||||
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
|
||||
return error;
|
||||
}
|
||||
|
||||
thread->retval[0] = io.offset - offset;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_freebsd6_pwrite(Thread *thread, sint fd,
|
||||
ptr<const void> buf, size_t nbyte,
|
||||
sint, off_t offset) {
|
||||
return sys_pwrite(thread, fd, buf, nbyte, offset);
|
||||
}
|
||||
orbis::SysResult orbis::sys_writev(Thread *thread, sint fd,
|
||||
ptr<struct iovec> iovp, uint iovcnt) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_writev(Thread *thread, sint fd, ptr<IoVec> iovp,
|
||||
uint iovcnt) {
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto write = file->ops->write;
|
||||
if (write == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
|
||||
Uio io{
|
||||
.offset = file->nextOff,
|
||||
.iov = iovp,
|
||||
.iovcnt = iovcnt,
|
||||
.segflg = UioSeg::UserSpace,
|
||||
.rw = UioRw::Write,
|
||||
.td = thread,
|
||||
};
|
||||
|
||||
auto error = write(file.get(), &io, thread);
|
||||
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
|
||||
return error;
|
||||
}
|
||||
|
||||
auto cnt = io.offset - file->nextOff;
|
||||
file->nextOff = io.offset;
|
||||
|
||||
thread->retval[0] = cnt;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_pwritev(Thread *thread, sint fd,
|
||||
ptr<struct iovec> iovp, uint iovcnt,
|
||||
off_t offset) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_pwritev(Thread *thread, sint fd, ptr<IoVec> iovp,
|
||||
uint iovcnt, off_t offset) {
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto write = file->ops->write;
|
||||
if (write == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
|
||||
Uio io{
|
||||
.offset = static_cast<std::uint64_t>(offset),
|
||||
.iov = iovp,
|
||||
.iovcnt = iovcnt,
|
||||
.segflg = UioSeg::UserSpace,
|
||||
.rw = UioRw::Write,
|
||||
.td = thread,
|
||||
};
|
||||
auto error = write(file.get(), &io, thread);
|
||||
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
|
||||
return error;
|
||||
}
|
||||
|
||||
thread->retval[0] = io.offset - offset;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_ftruncate(Thread *thread, sint fd, off_t length) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, fd, length);
|
||||
if (auto ftruncate = thread->tproc->ops->ftruncate) {
|
||||
return ftruncate(thread, fd, length);
|
||||
if (fd == 0) {
|
||||
return {}; // FIXME: remove when shm implemented
|
||||
}
|
||||
return ErrorCode::NOSYS;
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto truncate = file->ops->truncate;
|
||||
if (truncate == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
return truncate(file.get(), length, thread);
|
||||
}
|
||||
orbis::SysResult orbis::sys_freebsd6_ftruncate(Thread *thread, sint fd, sint,
|
||||
off_t length) {
|
||||
|
|
@ -77,10 +299,18 @@ orbis::SysResult orbis::sys_freebsd6_ftruncate(Thread *thread, sint fd, sint,
|
|||
orbis::SysResult orbis::sys_ioctl(Thread *thread, sint fd, ulong com,
|
||||
caddr_t data) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, fd, com);
|
||||
if (auto ioctl = thread->tproc->ops->ioctl) {
|
||||
return ioctl(thread, fd, com, data);
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
return ErrorCode::NOSYS;
|
||||
|
||||
auto ioctl = file->ops->ioctl;
|
||||
if (ioctl == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
return ioctl(file.get(), com, data, thread);
|
||||
}
|
||||
orbis::SysResult orbis::sys_pselect(Thread *thread, sint nd, ptr<fd_set> in,
|
||||
ptr<fd_set> ou, ptr<fd_set> ex,
|
||||
|
|
@ -117,12 +347,12 @@ orbis::SysResult orbis::sys_sysarch(Thread *thread, sint op, ptr<char> parms) {
|
|||
uint64_t fs;
|
||||
if (auto error = uread(fs, (ptr<uint64_t>)parms); error != ErrorCode{})
|
||||
return error;
|
||||
std::printf("sys_sysarch: set FS to 0x%zx\n", (std::size_t)fs);
|
||||
ORBIS_LOG_WARNING("sys_sysarch: set FS", (std::size_t)fs);
|
||||
thread->fsBase = fs;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::printf("sys_sysarch(op = %d, parms = %p): unknown op\n", op, parms);
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, op, parms);
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_nnpfs_syscall(Thread *thread, sint operation,
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
orbis::SysResult orbis::sys_jail(Thread *thread, ptr<struct jail> jail) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_jail_set(Thread *thread, ptr<struct iovec> iovp,
|
||||
orbis::SysResult orbis::sys_jail_set(Thread *thread, ptr<IoVec> iovp,
|
||||
uint iovcnt, sint flags) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_jail_get(Thread *thread, ptr<struct iovec> iovp,
|
||||
orbis::SysResult orbis::sys_jail_get(Thread *thread, ptr<IoVec> iovp,
|
||||
uint iovcnt, sint flags) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include "osem.hpp"
|
||||
#include "sys/sysproto.hpp"
|
||||
#include "utils/Logs.hpp"
|
||||
#include <chrono>
|
||||
|
||||
orbis::SysResult orbis::sys_netcontrol(Thread *thread, sint fd, uint op,
|
||||
ptr<void> buf, uint nbuf) {
|
||||
|
|
@ -24,18 +23,28 @@ orbis::SysResult orbis::sys_socketex(Thread *thread, ptr<const char> name,
|
|||
sint domain, sint type, sint protocol) {
|
||||
ORBIS_LOG_TODO(__FUNCTION__, name, domain, type, protocol);
|
||||
if (auto socket = thread->tproc->ops->socket) {
|
||||
return socket(thread, name, domain, type, protocol);
|
||||
Ref<File> file;
|
||||
auto result = socket(thread, name, domain, type, protocol, &file);
|
||||
|
||||
if (result.isError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto fd = thread->tproc->fileDescriptors.insert(file);
|
||||
ORBIS_LOG_WARNING("Socket opened", name, fd);
|
||||
thread->retval[0] = fd;
|
||||
return {};
|
||||
}
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_socketclose(Thread *thread, sint fd) {
|
||||
// This syscall is identical to sys_close
|
||||
ORBIS_LOG_NOTICE(__FUNCTION__, fd);
|
||||
if (auto close = thread->tproc->ops->close) {
|
||||
return close(thread, fd);
|
||||
if (thread->tproc->fileDescriptors.close(fd)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return ErrorCode::NOSYS;
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
orbis::SysResult orbis::sys_netgetiflist(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
|
|
|
|||
|
|
@ -82,12 +82,12 @@ orbis::sys_sctp_generic_sendmsg(Thread *thread, sint sd, caddr_t msg, sint mlen,
|
|||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_sctp_generic_sendmsg_iov(
|
||||
Thread *thread, sint sd, ptr<struct iovec> iov, sint iovlen, caddr_t to,
|
||||
Thread *thread, sint sd, ptr<IoVec> iov, sint iovlen, caddr_t to,
|
||||
__socklen_t tolen, ptr<struct sctp_sndrcvinfo> sinfo, sint flags) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult
|
||||
orbis::sys_sctp_generic_recvmsg(Thread *thread, sint sd, ptr<struct iovec> iov,
|
||||
orbis::sys_sctp_generic_recvmsg(Thread *thread, sint sd, ptr<IoVec> iov,
|
||||
sint iovlen, caddr_t from, __socklen_t fromlen,
|
||||
ptr<struct sctp_sndrcvinfo> sinfo, sint flags) {
|
||||
return ErrorCode::NOSYS;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,14 @@ orbis::SysResult orbis::sys_open(Thread *thread, ptr<char> path, sint flags,
|
|||
sint mode) {
|
||||
ORBIS_LOG_NOTICE("sys_open", path, flags, mode);
|
||||
if (auto open = thread->tproc->ops->open) {
|
||||
return open(thread, path, flags, mode);
|
||||
Ref<File> file;
|
||||
auto result = open(thread, path, flags, mode, &file);
|
||||
if (result.isError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
thread->retval[0] = thread->tproc->fileDescriptors.insert(file);
|
||||
return {};
|
||||
}
|
||||
|
||||
return ErrorCode::NOSYS;
|
||||
|
|
@ -84,10 +91,46 @@ orbis::SysResult orbis::sys_unlinkat(Thread *thread, sint fd, ptr<char> path,
|
|||
}
|
||||
orbis::SysResult orbis::sys_lseek(Thread *thread, sint fd, off_t offset,
|
||||
sint whence) {
|
||||
if (auto lseek = thread->tproc->ops->lseek) {
|
||||
return lseek(thread, fd, offset, whence);
|
||||
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
return ErrorCode::NOSYS;
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
|
||||
// TODO: use ioctl?
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
file->nextOff = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
file->nextOff += offset;
|
||||
break;
|
||||
|
||||
case SEEK_END: {
|
||||
if (file->ops->stat == nullptr) {
|
||||
ORBIS_LOG_ERROR("seek with end whence: unimplemented stat");
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
orbis::Stat stat;
|
||||
auto result = file->ops->stat(file.get(), &stat, thread);
|
||||
if (result != ErrorCode{}) {
|
||||
return result;
|
||||
}
|
||||
|
||||
file->nextOff = stat.size + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ORBIS_LOG_ERROR("sys_lseek: unimplemented whence", whence);
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
|
||||
thread->retval[0] = file->nextOff;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_freebsd6_lseek(Thread *thread, sint fd, sint,
|
||||
off_t offset, sint whence) {
|
||||
|
|
@ -105,35 +148,30 @@ orbis::SysResult orbis::sys_eaccess(Thread *thread, ptr<char> path,
|
|||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_stat(Thread *thread, ptr<char> path, ptr<Stat> ub) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, path, ub);
|
||||
auto result = sys_open(thread, path, 0, 0);
|
||||
Ref<File> file;
|
||||
auto result = thread->tproc->ops->open(thread, path, 0, 0, &file);
|
||||
if (result.isError()) {
|
||||
return ErrorCode::NOENT;
|
||||
}
|
||||
|
||||
auto fd = thread->retval[0];
|
||||
result = sys_lseek(thread, fd, 0, SEEK_END);
|
||||
if (result.isError()) {
|
||||
sys_close(thread, fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
auto len = thread->retval[0];
|
||||
result = sys_pread(thread, fd, ub, 1, 0);
|
||||
if (result.isError()) {
|
||||
*ub = {};
|
||||
ub->mode = 0777 | 0x4000;
|
||||
} else {
|
||||
*ub = {};
|
||||
ub->size = len;
|
||||
ub->blksize = 1;
|
||||
ub->blocks = len;
|
||||
ub->mode = 0777 | 0x8000;
|
||||
auto stat = file->ops->stat;
|
||||
if (stat == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
sys_close(thread, fd);
|
||||
thread->retval[0] = 0;
|
||||
return {};
|
||||
std::lock_guard lock(file->mtx);
|
||||
Stat _ub;
|
||||
result = uread(_ub, ub);
|
||||
if (result.isError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = stat(file.get(), &_ub, thread);
|
||||
if (result.isError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return uwrite(ub, _ub);
|
||||
}
|
||||
orbis::SysResult orbis::sys_fstatat(Thread *thread, sint fd, ptr<char> path,
|
||||
ptr<Stat> buf, sint flag) {
|
||||
|
|
@ -226,18 +264,25 @@ orbis::SysResult orbis::sys_futimes(Thread *thread, sint fd,
|
|||
}
|
||||
orbis::SysResult orbis::sys_truncate(Thread *thread, ptr<char> path,
|
||||
off_t length) {
|
||||
if (auto truncate = thread->tproc->ops->truncate) {
|
||||
return truncate(thread, path, length);
|
||||
Ref<File> file;
|
||||
auto result = thread->tproc->ops->open(thread, path, 0, 0, &file);
|
||||
if (result.isError()) {
|
||||
return result;
|
||||
}
|
||||
return ErrorCode::NOSYS;
|
||||
|
||||
auto truncate = file->ops->truncate;
|
||||
if (truncate == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mtx);
|
||||
return truncate(file.get(), length, thread);
|
||||
}
|
||||
orbis::SysResult orbis::sys_freebsd6_truncate(Thread *thread, ptr<char> path,
|
||||
sint, off_t length) {
|
||||
return sys_truncate(thread, path, length);
|
||||
}
|
||||
orbis::SysResult orbis::sys_fsync(Thread *thread, sint fd) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_fsync(Thread *thread, sint fd) { return {}; }
|
||||
orbis::SysResult orbis::sys_rename(Thread *thread, ptr<char> from,
|
||||
ptr<char> to) {
|
||||
return ErrorCode::NOSYS;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ orbis::SysResult orbis::sys_unmount(Thread *thread, ptr<char> path,
|
|||
sint flags) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_nmount(Thread *thread, ptr<struct iovec> iovp,
|
||||
uint iovcnt, sint flags) {
|
||||
orbis::SysResult orbis::sys_nmount(Thread *thread, ptr<IoVec> iovp, uint iovcnt,
|
||||
sint flags) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "utils/Logs.hpp"
|
||||
#include "error/ErrorCode.hpp"
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
|
|
@ -168,6 +169,298 @@ void log_class_string<bool>::format(std::string &out, const void *arg) {
|
|||
out += get_object(arg) ? "1" : "0";
|
||||
}
|
||||
|
||||
template <>
|
||||
void log_class_string<orbis::ErrorCode>::format(std::string &out,
|
||||
const void *arg) {
|
||||
auto errorCode = get_object(arg);
|
||||
switch (errorCode) {
|
||||
case ErrorCode::PERM:
|
||||
out += "PERM";
|
||||
return;
|
||||
case ErrorCode::NOENT:
|
||||
out += "NOENT";
|
||||
return;
|
||||
case ErrorCode::SRCH:
|
||||
out += "SRCH";
|
||||
return;
|
||||
case ErrorCode::INTR:
|
||||
out += "INTR";
|
||||
return;
|
||||
case ErrorCode::IO:
|
||||
out += "IO";
|
||||
return;
|
||||
case ErrorCode::NXIO:
|
||||
out += "NXIO";
|
||||
return;
|
||||
case ErrorCode::TOOBIG:
|
||||
out += "TOOBIG";
|
||||
return;
|
||||
case ErrorCode::NOEXEC:
|
||||
out += "NOEXEC";
|
||||
return;
|
||||
case ErrorCode::BADF:
|
||||
out += "BADF";
|
||||
return;
|
||||
case ErrorCode::CHILD:
|
||||
out += "CHILD";
|
||||
return;
|
||||
case ErrorCode::DEADLK:
|
||||
out += "DEADLK";
|
||||
return;
|
||||
case ErrorCode::NOMEM:
|
||||
out += "NOMEM";
|
||||
return;
|
||||
case ErrorCode::ACCES:
|
||||
out += "ACCES";
|
||||
return;
|
||||
case ErrorCode::FAULT:
|
||||
out += "FAULT";
|
||||
return;
|
||||
case ErrorCode::NOTBLK:
|
||||
out += "NOTBLK";
|
||||
return;
|
||||
case ErrorCode::BUSY:
|
||||
out += "BUSY";
|
||||
return;
|
||||
case ErrorCode::EXIST:
|
||||
out += "EXIST";
|
||||
return;
|
||||
case ErrorCode::XDEV:
|
||||
out += "XDEV";
|
||||
return;
|
||||
case ErrorCode::NODEV:
|
||||
out += "NODEV";
|
||||
return;
|
||||
case ErrorCode::NOTDIR:
|
||||
out += "NOTDIR";
|
||||
return;
|
||||
case ErrorCode::ISDIR:
|
||||
out += "ISDIR";
|
||||
return;
|
||||
case ErrorCode::INVAL:
|
||||
out += "INVAL";
|
||||
return;
|
||||
case ErrorCode::NFILE:
|
||||
out += "NFILE";
|
||||
return;
|
||||
case ErrorCode::MFILE:
|
||||
out += "MFILE";
|
||||
return;
|
||||
case ErrorCode::NOTTY:
|
||||
out += "NOTTY";
|
||||
return;
|
||||
case ErrorCode::TXTBSY:
|
||||
out += "TXTBSY";
|
||||
return;
|
||||
case ErrorCode::FBIG:
|
||||
out += "FBIG";
|
||||
return;
|
||||
case ErrorCode::NOSPC:
|
||||
out += "NOSPC";
|
||||
return;
|
||||
case ErrorCode::SPIPE:
|
||||
out += "SPIPE";
|
||||
return;
|
||||
case ErrorCode::ROFS:
|
||||
out += "ROFS";
|
||||
return;
|
||||
case ErrorCode::MLINK:
|
||||
out += "MLINK";
|
||||
return;
|
||||
case ErrorCode::PIPE:
|
||||
out += "PIPE";
|
||||
return;
|
||||
case ErrorCode::DOM:
|
||||
out += "DOM";
|
||||
return;
|
||||
case ErrorCode::RANGE:
|
||||
out += "RANGE";
|
||||
return;
|
||||
case ErrorCode::AGAIN:
|
||||
out += "AGAIN";
|
||||
return;
|
||||
case ErrorCode::INPROGRESS:
|
||||
out += "INPROGRESS";
|
||||
return;
|
||||
case ErrorCode::ALREADY:
|
||||
out += "ALREADY";
|
||||
return;
|
||||
case ErrorCode::NOTSOCK:
|
||||
out += "NOTSOCK";
|
||||
return;
|
||||
case ErrorCode::DESTADDRREQ:
|
||||
out += "DESTADDRREQ";
|
||||
return;
|
||||
case ErrorCode::MSGSIZE:
|
||||
out += "MSGSIZE";
|
||||
return;
|
||||
case ErrorCode::PROTOTYPE:
|
||||
out += "PROTOTYPE";
|
||||
return;
|
||||
case ErrorCode::NOPROTOOPT:
|
||||
out += "NOPROTOOPT";
|
||||
return;
|
||||
case ErrorCode::PROTONOSUPPORT:
|
||||
out += "PROTONOSUPPORT";
|
||||
return;
|
||||
case ErrorCode::SOCKTNOSUPPORT:
|
||||
out += "SOCKTNOSUPPORT";
|
||||
return;
|
||||
case ErrorCode::OPNOTSUPP:
|
||||
out += "OPNOTSUPP";
|
||||
return;
|
||||
case ErrorCode::PFNOSUPPORT:
|
||||
out += "PFNOSUPPORT";
|
||||
return;
|
||||
case ErrorCode::AFNOSUPPORT:
|
||||
out += "AFNOSUPPORT";
|
||||
return;
|
||||
case ErrorCode::ADDRINUSE:
|
||||
out += "ADDRINUSE";
|
||||
return;
|
||||
case ErrorCode::ADDRNOTAVAIL:
|
||||
out += "ADDRNOTAVAIL";
|
||||
return;
|
||||
case ErrorCode::NETDOWN:
|
||||
out += "NETDOWN";
|
||||
return;
|
||||
case ErrorCode::NETUNREACH:
|
||||
out += "NETUNREACH";
|
||||
return;
|
||||
case ErrorCode::NETRESET:
|
||||
out += "NETRESET";
|
||||
return;
|
||||
case ErrorCode::CONNABORTED:
|
||||
out += "CONNABORTED";
|
||||
return;
|
||||
case ErrorCode::CONNRESET:
|
||||
out += "CONNRESET";
|
||||
return;
|
||||
case ErrorCode::NOBUFS:
|
||||
out += "NOBUFS";
|
||||
return;
|
||||
case ErrorCode::ISCONN:
|
||||
out += "ISCONN";
|
||||
return;
|
||||
case ErrorCode::NOTCONN:
|
||||
out += "NOTCONN";
|
||||
return;
|
||||
case ErrorCode::SHUTDOWN:
|
||||
out += "SHUTDOWN";
|
||||
return;
|
||||
case ErrorCode::TOOMANYREFS:
|
||||
out += "TOOMANYREFS";
|
||||
return;
|
||||
case ErrorCode::TIMEDOUT:
|
||||
out += "TIMEDOUT";
|
||||
return;
|
||||
case ErrorCode::CONNREFUSED:
|
||||
out += "CONNREFUSED";
|
||||
return;
|
||||
case ErrorCode::LOOP:
|
||||
out += "LOOP";
|
||||
return;
|
||||
case ErrorCode::NAMETOOLONG:
|
||||
out += "NAMETOOLONG";
|
||||
return;
|
||||
case ErrorCode::HOSTDOWN:
|
||||
out += "HOSTDOWN";
|
||||
return;
|
||||
case ErrorCode::HOSTUNREACH:
|
||||
out += "HOSTUNREACH";
|
||||
return;
|
||||
case ErrorCode::NOTEMPTY:
|
||||
out += "NOTEMPTY";
|
||||
return;
|
||||
case ErrorCode::PROCLIM:
|
||||
out += "PROCLIM";
|
||||
return;
|
||||
case ErrorCode::USERS:
|
||||
out += "USERS";
|
||||
return;
|
||||
case ErrorCode::DQUOT:
|
||||
out += "DQUOT";
|
||||
return;
|
||||
case ErrorCode::STALE:
|
||||
out += "STALE";
|
||||
return;
|
||||
case ErrorCode::REMOTE:
|
||||
out += "REMOTE";
|
||||
return;
|
||||
case ErrorCode::BADRPC:
|
||||
out += "BADRPC";
|
||||
return;
|
||||
case ErrorCode::RPCMISMATCH:
|
||||
out += "RPCMISMATCH";
|
||||
return;
|
||||
case ErrorCode::PROGUNAVAIL:
|
||||
out += "PROGUNAVAIL";
|
||||
return;
|
||||
case ErrorCode::PROGMISMATCH:
|
||||
out += "PROGMISMATCH";
|
||||
return;
|
||||
case ErrorCode::PROCUNAVAIL:
|
||||
out += "PROCUNAVAIL";
|
||||
return;
|
||||
case ErrorCode::NOLCK:
|
||||
out += "NOLCK";
|
||||
return;
|
||||
case ErrorCode::NOSYS:
|
||||
out += "NOSYS";
|
||||
return;
|
||||
case ErrorCode::FTYPE:
|
||||
out += "FTYPE";
|
||||
return;
|
||||
case ErrorCode::AUTH:
|
||||
out += "AUTH";
|
||||
return;
|
||||
case ErrorCode::NEEDAUTH:
|
||||
out += "NEEDAUTH";
|
||||
return;
|
||||
case ErrorCode::IDRM:
|
||||
out += "IDRM";
|
||||
return;
|
||||
case ErrorCode::NOMSG:
|
||||
out += "NOMSG";
|
||||
return;
|
||||
case ErrorCode::OVERFLOW:
|
||||
out += "OVERFLOW";
|
||||
return;
|
||||
case ErrorCode::CANCELED:
|
||||
out += "CANCELED";
|
||||
return;
|
||||
case ErrorCode::ILSEQ:
|
||||
out += "ILSEQ";
|
||||
return;
|
||||
case ErrorCode::NOATTR:
|
||||
out += "NOATTR";
|
||||
return;
|
||||
case ErrorCode::DOOFUS:
|
||||
out += "DOOFUS";
|
||||
return;
|
||||
case ErrorCode::BADMSG:
|
||||
out += "BADMSG";
|
||||
return;
|
||||
case ErrorCode::MULTIHOP:
|
||||
out += "MULTIHOP";
|
||||
return;
|
||||
case ErrorCode::NOLINK:
|
||||
out += "NOLINK";
|
||||
return;
|
||||
case ErrorCode::PROTO:
|
||||
out += "PROTO";
|
||||
return;
|
||||
case ErrorCode::NOTCAPABLE:
|
||||
out += "NOTCAPABLE";
|
||||
return;
|
||||
case ErrorCode::CAPMODE:
|
||||
out += "CAPMODE";
|
||||
return;
|
||||
}
|
||||
|
||||
out += "<unknown " + std::to_string((int)errorCode) + ">";
|
||||
}
|
||||
|
||||
void _orbis_log_print(LogLevel lvl, std::string_view msg,
|
||||
std::string_view names, const log_type_info *sup, ...) {
|
||||
if (lvl > logs_level.load(std::memory_order::relaxed)) {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ add_executable(rpcsx-os
|
|||
iodev/hmd_snsr.cpp
|
||||
iodev/null.cpp
|
||||
iodev/rng.cpp
|
||||
iodev/stderr.cpp
|
||||
iodev/stdin.cpp
|
||||
iodev/stdout.cpp
|
||||
iodev/zero.cpp
|
||||
|
||||
main.cpp
|
||||
|
|
|
|||
|
|
@ -1,70 +1,221 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/stat.hpp"
|
||||
#include "orbis/uio.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include <cerrno>
|
||||
#include <fcntl.h>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
std::int64_t io_device_instance_close(IoDeviceInstance *instance) { return 0; }
|
||||
struct HostFile : orbis::File {
|
||||
int hostFd = -1;
|
||||
|
||||
void io_device_instance_init(IoDevice *device, IoDeviceInstance *instance) {
|
||||
if (instance->device == nullptr) {
|
||||
instance->device = device;
|
||||
~HostFile() {
|
||||
if (hostFd > 0) {
|
||||
::close(hostFd);
|
||||
}
|
||||
}
|
||||
|
||||
if (instance->close == nullptr) {
|
||||
instance->close = io_device_instance_close;
|
||||
}
|
||||
}
|
||||
|
||||
struct HostIoDevice : IoDevice {
|
||||
orbis::utils::kstring hostPath;
|
||||
};
|
||||
|
||||
struct HostIoDeviceInstance : IoDeviceInstance {
|
||||
int hostFd;
|
||||
};
|
||||
|
||||
struct SocketDeviceInstance : IoDeviceInstance {
|
||||
struct SocketFile : orbis::File {
|
||||
orbis::utils::kstring name;
|
||||
int hostFd;
|
||||
int hostFd = -1;
|
||||
|
||||
~SocketFile() {
|
||||
if (hostFd > 0) {
|
||||
::close(hostFd);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static std::int64_t host_io_device_instance_read(IoDeviceInstance *instance,
|
||||
void *data,
|
||||
std::uint64_t size) {
|
||||
auto hostIoInstance = static_cast<HostIoDeviceInstance *>(instance);
|
||||
return ::read(hostIoInstance->hostFd, data, size); // TODO: convert errno
|
||||
struct HostFsDevice : IoDevice {
|
||||
orbis::kstring hostPath;
|
||||
|
||||
explicit HostFsDevice(orbis::kstring path) : hostPath(std::move(path)) {}
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
|
||||
static orbis::ErrorCode convertErrno() {
|
||||
switch (auto error = errno) {
|
||||
case EPERM:
|
||||
return orbis::ErrorCode::PERM;
|
||||
case ENOENT:
|
||||
return orbis::ErrorCode::NOENT;
|
||||
case EBADF:
|
||||
return orbis::ErrorCode::BADF;
|
||||
case EIO:
|
||||
return orbis::ErrorCode::IO;
|
||||
case EACCES:
|
||||
return orbis::ErrorCode::ACCES;
|
||||
case EEXIST:
|
||||
return orbis::ErrorCode::EXIST;
|
||||
case EBUSY:
|
||||
return orbis::ErrorCode::BUSY;
|
||||
case ENOTDIR:
|
||||
return orbis::ErrorCode::NOTDIR;
|
||||
case EISDIR:
|
||||
return orbis::ErrorCode::ISDIR;
|
||||
case EFBIG:
|
||||
return orbis::ErrorCode::FBIG;
|
||||
case ENOSPC:
|
||||
return orbis::ErrorCode::NOSPC;
|
||||
case ESPIPE:
|
||||
return orbis::ErrorCode::SPIPE;
|
||||
case EPIPE:
|
||||
return orbis::ErrorCode::PIPE;
|
||||
|
||||
default:
|
||||
ORBIS_LOG_ERROR("Unconverted errno", error);
|
||||
}
|
||||
|
||||
return orbis::ErrorCode::IO;
|
||||
}
|
||||
|
||||
static std::int64_t host_io_device_instance_write(IoDeviceInstance *instance,
|
||||
const void *data,
|
||||
std::uint64_t size) {
|
||||
auto hostIoInstance = static_cast<HostIoDeviceInstance *>(instance);
|
||||
return ::write(hostIoInstance->hostFd, data, size); // TODO: convert errno
|
||||
static orbis::ErrorCode host_read(orbis::File *file, orbis::Uio *uio,
|
||||
orbis::Thread *) {
|
||||
auto hostFile = static_cast<HostFile *>(file);
|
||||
std::vector<iovec> vec;
|
||||
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
|
||||
vec.push_back({.iov_base = entry.base, .iov_len = entry.len});
|
||||
}
|
||||
|
||||
ssize_t cnt;
|
||||
if (hostFile->hostFd == 0) {
|
||||
cnt = ::read(hostFile->hostFd, vec.data(), vec.size());
|
||||
} else {
|
||||
cnt = ::preadv(hostFile->hostFd, vec.data(), vec.size(), uio->offset);
|
||||
}
|
||||
if (cnt < 0) {
|
||||
return convertErrno();
|
||||
}
|
||||
|
||||
uio->resid -= cnt;
|
||||
uio->offset += cnt;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int64_t host_io_device_instance_lseek(IoDeviceInstance *instance,
|
||||
std::uint64_t offset,
|
||||
std::uint32_t whence) {
|
||||
auto hostIoInstance = static_cast<HostIoDeviceInstance *>(instance);
|
||||
static orbis::ErrorCode host_write(orbis::File *file, orbis::Uio *uio,
|
||||
orbis::Thread *) {
|
||||
auto hostFile = static_cast<HostFile *>(file);
|
||||
std::vector<iovec> vec;
|
||||
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
|
||||
vec.push_back({.iov_base = entry.base, .iov_len = entry.len});
|
||||
}
|
||||
|
||||
return ::lseek(hostIoInstance->hostFd, offset, whence); // TODO: convert errno
|
||||
ssize_t cnt;
|
||||
if (hostFile->hostFd == 1 || hostFile->hostFd == 2) {
|
||||
cnt = ::write(hostFile->hostFd, vec.data(), vec.size());
|
||||
} else {
|
||||
cnt = ::pwritev(hostFile->hostFd, vec.data(), vec.size(), uio->offset);
|
||||
}
|
||||
if (cnt < 0) {
|
||||
return convertErrno();
|
||||
}
|
||||
|
||||
uio->resid -= cnt;
|
||||
uio->offset += cnt;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int64_t host_io_device_instance_close(IoDeviceInstance *instance) {
|
||||
auto hostIoInstance = static_cast<HostIoDeviceInstance *>(instance);
|
||||
::close(hostIoInstance->hostFd);
|
||||
return io_device_instance_close(instance);
|
||||
static orbis::ErrorCode host_stat(orbis::File *file, orbis::Stat *sb,
|
||||
orbis::Thread *thread) {
|
||||
auto hostFile = static_cast<HostFile *>(file);
|
||||
struct stat hostStat;
|
||||
::fstat(hostFile->hostFd, &hostStat);
|
||||
sb->dev = hostStat.st_dev; // TODO
|
||||
sb->ino = hostStat.st_ino;
|
||||
sb->mode = hostStat.st_mode;
|
||||
sb->nlink = hostStat.st_nlink;
|
||||
sb->uid = hostStat.st_uid;
|
||||
sb->gid = hostStat.st_gid;
|
||||
sb->rdev = hostStat.st_rdev;
|
||||
sb->atim = {
|
||||
.sec = static_cast<uint64_t>(hostStat.st_atim.tv_sec),
|
||||
.nsec = static_cast<uint64_t>(hostStat.st_atim.tv_nsec),
|
||||
};
|
||||
sb->mtim = {
|
||||
.sec = static_cast<uint64_t>(hostStat.st_mtim.tv_sec),
|
||||
.nsec = static_cast<uint64_t>(hostStat.st_mtim.tv_nsec),
|
||||
};
|
||||
sb->ctim = {
|
||||
.sec = static_cast<uint64_t>(hostStat.st_mtim.tv_sec),
|
||||
.nsec = static_cast<uint64_t>(hostStat.st_mtim.tv_nsec),
|
||||
};
|
||||
sb->size = hostStat.st_size;
|
||||
sb->blocks = hostStat.st_blocks;
|
||||
sb->blksize = hostStat.st_blksize;
|
||||
// TODO
|
||||
sb->flags = 0;
|
||||
sb->gen = 0;
|
||||
sb->lspare = 0;
|
||||
sb->birthtim = {
|
||||
.sec = static_cast<uint64_t>(hostStat.st_mtim.tv_sec),
|
||||
.nsec = static_cast<uint64_t>(hostStat.st_mtim.tv_nsec),
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t host_io_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto hostDevice = static_cast<HostIoDevice *>(device);
|
||||
auto realPath = hostDevice->hostPath + "/" + path;
|
||||
static orbis::ErrorCode host_truncate(orbis::File *file, std::uint64_t len,
|
||||
orbis::Thread *thread) {
|
||||
auto hostFile = static_cast<HostFile *>(file);
|
||||
if (::ftruncate(hostFile->hostFd, len)) {
|
||||
return convertErrno();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static orbis::ErrorCode socket_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
auto soc = static_cast<SocketFile *>(file);
|
||||
ORBIS_LOG_FATAL("Unhandled socket ioctl", request, soc->name);
|
||||
return {};
|
||||
}
|
||||
|
||||
static const orbis::FileOps hostOps = {
|
||||
.read = host_read,
|
||||
.write = host_write,
|
||||
.truncate = host_truncate,
|
||||
.stat = host_stat,
|
||||
};
|
||||
|
||||
static const orbis::FileOps socketOps = {
|
||||
.ioctl = socket_ioctl,
|
||||
};
|
||||
|
||||
IoDevice *createHostIoDevice(orbis::kstring hostPath) {
|
||||
return orbis::knew<HostFsDevice>(std::move(hostPath));
|
||||
}
|
||||
|
||||
orbis::ErrorCode createSocket(orbis::Ref<orbis::File> *file,
|
||||
orbis::kstring name, int dom, int type,
|
||||
int prot) {
|
||||
auto fd = ::socket(dom, type, prot);
|
||||
if (fd < 0) {
|
||||
return convertErrno();
|
||||
}
|
||||
|
||||
auto s = orbis::knew<SocketFile>();
|
||||
s->name = std::move(name);
|
||||
s->hostFd = fd;
|
||||
s->ops = &socketOps;
|
||||
*file = s;
|
||||
return {};
|
||||
}
|
||||
|
||||
orbis::ErrorCode HostFsDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto realPath = hostPath + "/" + path;
|
||||
|
||||
int realFlags = flags & O_ACCMODE;
|
||||
flags &= ~O_ACCMODE;
|
||||
|
|
@ -104,59 +255,51 @@ static std::int32_t host_io_open(IoDevice *device,
|
|||
flags &= ~kOpenFlagExcl;
|
||||
}
|
||||
|
||||
if ((flags & kOpenFlagDirectory) != 0) {
|
||||
realFlags |= O_DIRECTORY;
|
||||
flags &= ~kOpenFlagDirectory;
|
||||
}
|
||||
|
||||
if (flags != 0) {
|
||||
std::fprintf(stderr, "host_io_open: ***ERROR*** Unhandled open flags %x\n",
|
||||
flags);
|
||||
ORBIS_LOG_ERROR("host_open: ***ERROR*** Unhandled open flags", flags);
|
||||
}
|
||||
|
||||
int hostFd = ::open(realPath.c_str(), realFlags, 0777);
|
||||
|
||||
if (hostFd < 0) {
|
||||
std::fprintf(stderr, "host_io_open: '%s' not found.\n", realPath.c_str());
|
||||
return 1; // TODO: convert errno
|
||||
auto error = convertErrno();
|
||||
ORBIS_LOG_ERROR("host_open failed", realPath, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
auto newInstance = orbis::knew<HostIoDeviceInstance>();
|
||||
|
||||
newInstance->hostFd = hostFd;
|
||||
|
||||
newInstance->read = host_io_device_instance_read;
|
||||
newInstance->write = host_io_device_instance_write;
|
||||
newInstance->lseek = host_io_device_instance_lseek;
|
||||
newInstance->close = host_io_device_instance_close;
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
}
|
||||
|
||||
IoDevice *createHostIoDevice(const char *hostPath) {
|
||||
auto result = orbis::knew<HostIoDevice>();
|
||||
result->open = host_io_open;
|
||||
result->hostPath = hostPath;
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::int64_t socket_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
|
||||
ORBIS_LOG_FATAL("Unhandled socket ioctl", request);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::int64_t socket_instance_close(IoDeviceInstance *instance) {
|
||||
::close(static_cast<SocketDeviceInstance *>(instance)->hostFd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
orbis::ErrorCode createSocket(const char *name, int dom, int type, int prot,
|
||||
orbis::Ref<IoDeviceInstance> *instance) {
|
||||
auto s = orbis::knew<SocketDeviceInstance>();
|
||||
s->ioctl = socket_instance_ioctl;
|
||||
s->close = socket_instance_close;
|
||||
s->name = name;
|
||||
s->hostFd = ::socket(dom, type, prot);
|
||||
*instance = s;
|
||||
auto newFile = orbis::knew<HostFile>();
|
||||
newFile->hostFd = hostFd;
|
||||
newFile->ops = &hostOps;
|
||||
newFile->device = this;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
orbis::File *createHostFile(int hostFd, orbis::Ref<IoDevice> device) {
|
||||
auto newFile = orbis::knew<HostFile>();
|
||||
newFile->hostFd = hostFd;
|
||||
newFile->ops = &hostOps;
|
||||
newFile->device = device;
|
||||
return newFile;
|
||||
}
|
||||
|
||||
struct FdWrapDevice : public IoDevice {
|
||||
int fd;
|
||||
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override {
|
||||
*file = createHostFile(fd, this);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
IoDevice *createFdWrapDevice(int fd) {
|
||||
auto result = orbis::knew<FdWrapDevice>();
|
||||
result->fd = fd;
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Rc.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
struct IoDevice;
|
||||
namespace orbis {
|
||||
enum class ErrorCode : int;
|
||||
}
|
||||
|
||||
enum OpenFlags {
|
||||
kOpenFlagReadOnly = 0x0,
|
||||
kOpenFlagWriteOnly = 0x1,
|
||||
|
|
@ -26,36 +23,13 @@ enum OpenFlags {
|
|||
kOpenFlagDirectory = 0x20000,
|
||||
};
|
||||
|
||||
struct IoDeviceInstance : orbis::RcBase {
|
||||
orbis::Ref<IoDevice> device;
|
||||
|
||||
std::int64_t (*ioctl)(IoDeviceInstance *instance, std::uint64_t request,
|
||||
void *argp) = nullptr;
|
||||
|
||||
std::int64_t (*write)(IoDeviceInstance *instance, const void *data,
|
||||
std::uint64_t size) = nullptr;
|
||||
std::int64_t (*read)(IoDeviceInstance *instance, void *data,
|
||||
std::uint64_t size) = nullptr;
|
||||
std::int64_t (*close)(IoDeviceInstance *instance) = nullptr;
|
||||
std::int64_t (*lseek)(IoDeviceInstance *instance, std::uint64_t offset,
|
||||
std::uint32_t whence) = nullptr;
|
||||
|
||||
void *(*mmap)(IoDeviceInstance *instance, void *address, std::uint64_t size,
|
||||
std::int32_t prot, std::int32_t flags,
|
||||
std::int64_t offset) = nullptr;
|
||||
void *(*munmap)(IoDeviceInstance *instance, void *address,
|
||||
std::uint64_t size) = nullptr;
|
||||
};
|
||||
|
||||
struct IoDevice : orbis::RcBase {
|
||||
std::int32_t (*open)(IoDevice *device, orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) = nullptr;
|
||||
virtual orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) = 0;
|
||||
};
|
||||
|
||||
std::int64_t io_device_instance_close(IoDeviceInstance *instance);
|
||||
void io_device_instance_init(IoDevice *device, IoDeviceInstance *instance);
|
||||
|
||||
IoDevice *createHostIoDevice(const char *hostPath);
|
||||
orbis::ErrorCode createSocket(const char *name, int dom, int type, int prot,
|
||||
orbis::Ref<IoDeviceInstance> *instance);
|
||||
IoDevice *createHostIoDevice(orbis::kstring hostPath);
|
||||
orbis::ErrorCode createSocket(orbis::Ref<orbis::File> *file,
|
||||
orbis::kstring name, int dom, int type, int prot);
|
||||
orbis::File *createHostFile(int hostFd, orbis::Ref<IoDevice> device);
|
||||
IoDevice *createFdWrapDevice(int fd);
|
||||
|
|
|
|||
|
|
@ -12,9 +12,6 @@ IoDevice *createHmdCmdCharacterDevice();
|
|||
IoDevice *createHmdMmapCharacterDevice();
|
||||
IoDevice *createHmdSnsrCharacterDevice();
|
||||
IoDevice *createNullCharacterDevice();
|
||||
IoDevice *createStderrCharacterDevice();
|
||||
IoDevice *createStdinCharacterDevice();
|
||||
IoDevice *createStdoutCharacterDevice();
|
||||
IoDevice *createZeroCharacterDevice();
|
||||
IoDevice *createRngCharacterDevice();
|
||||
IoDevice *createAjmCharacterDevice();
|
||||
|
|
|
|||
|
|
@ -1,33 +1,31 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
struct AjmDevice : public IoDevice {};
|
||||
struct AjmFile : orbis::File {};
|
||||
|
||||
struct AjmInstance : public IoDeviceInstance {};
|
||||
|
||||
static std::int64_t ajm_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
|
||||
ORBIS_LOG_FATAL("Unhandled AJM ioctl", request);
|
||||
return -1;
|
||||
return orbis::ErrorCode::PERM;
|
||||
}
|
||||
|
||||
static std::int32_t ajm_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<AjmInstance>();
|
||||
newInstance->ioctl = ajm_instance_ioctl;
|
||||
static const orbis::FileOps fileOps = {
|
||||
.ioctl = ajm_ioctl,
|
||||
};
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
}
|
||||
struct AjmDevice : IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override {
|
||||
auto newFile = orbis::knew<AjmFile>();
|
||||
newFile->ops = &fileOps;
|
||||
newFile->device = this;
|
||||
|
||||
IoDevice *createAjmCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<AjmDevice>();
|
||||
newDevice->open = ajm_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
IoDevice *createAjmCharacterDevice() { return orbis::knew<AjmDevice>(); }
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/error/ErrorCode.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include "orbis/utils/SharedMutex.hpp"
|
||||
#include "vm.hpp"
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
||||
struct VideoOutBuffer {
|
||||
std::uint32_t pixelFormat;
|
||||
|
|
@ -17,12 +18,6 @@ struct VideoOutBuffer {
|
|||
std::uint32_t height;
|
||||
};
|
||||
|
||||
struct DceDevice : public IoDevice {};
|
||||
|
||||
struct DceInstance : public IoDeviceInstance {
|
||||
VideoOutBuffer bufferAttributes{};
|
||||
};
|
||||
|
||||
struct RegisterBuffer {
|
||||
std::uint64_t attributeIndex;
|
||||
std::uint64_t index;
|
||||
|
|
@ -87,9 +82,20 @@ struct ResolutionStatus {
|
|||
std::uint32_t y;
|
||||
};
|
||||
|
||||
static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
auto dceInstance = static_cast<DceInstance *>(instance);
|
||||
struct DceFile : public orbis::File {};
|
||||
|
||||
struct DceDevice : IoDevice {
|
||||
orbis::shared_mutex mtx;
|
||||
VideoOutBuffer bufferAttributes{}; // TODO
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
|
||||
static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
auto device = static_cast<DceDevice *>(file->device.get());
|
||||
|
||||
std::lock_guard lock(device->mtx);
|
||||
|
||||
if (request == 0xc0308203) {
|
||||
// returns:
|
||||
|
|
@ -122,7 +128,7 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
args->size);
|
||||
} else if (args->id == 10) {
|
||||
if (args->size != sizeof(FlipControlStatus)) {
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
FlipControlStatus flipStatus{};
|
||||
|
|
@ -154,10 +160,10 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
*(std::uint64_t *)args->size = 0x100000; // size
|
||||
} else if (args->id == 31) {
|
||||
rx::bridge.header->bufferInUseAddress = args->size;
|
||||
return 0;
|
||||
return {};
|
||||
} else if (args->id == 33) { // adjust color
|
||||
std::printf("adjust color\n");
|
||||
return 0;
|
||||
return {};
|
||||
} else if (args->id != 0 && args->id != 1) { // used during open/close
|
||||
ORBIS_LOG_NOTICE("dce: UNIMPLEMENTED FlipControl", args->id, args->arg2,
|
||||
args->ptr, args->size);
|
||||
|
|
@ -165,7 +171,7 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
std::fflush(stdout);
|
||||
//__builtin_trap();
|
||||
}
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (request == 0xc0308206) {
|
||||
|
|
@ -176,18 +182,18 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
if (args->index >= std::size(rx::bridge.header->buffers)) {
|
||||
// TODO
|
||||
ORBIS_LOG_FATAL("dce: out of buffers!");
|
||||
return -1;
|
||||
return orbis::ErrorCode::NOMEM;
|
||||
}
|
||||
|
||||
// TODO: lock bridge header
|
||||
rx::bridge.header->buffers[args->index] = {
|
||||
.width = dceInstance->bufferAttributes.width,
|
||||
.height = dceInstance->bufferAttributes.height,
|
||||
.pitch = dceInstance->bufferAttributes.pitch,
|
||||
.width = device->bufferAttributes.width,
|
||||
.height = device->bufferAttributes.height,
|
||||
.pitch = device->bufferAttributes.pitch,
|
||||
.address = args->address,
|
||||
.pixelFormat = dceInstance->bufferAttributes.pixelFormat,
|
||||
.tilingMode = dceInstance->bufferAttributes.tilingMode};
|
||||
return 0;
|
||||
.pixelFormat = device->bufferAttributes.pixelFormat,
|
||||
.tilingMode = device->bufferAttributes.tilingMode};
|
||||
return {};
|
||||
}
|
||||
|
||||
if (request == 0xc0308207) { // SCE_SYS_DCE_IOCTL_REGISTER_BUFFER_ATTRIBUTE
|
||||
|
|
@ -199,12 +205,12 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
args->unk4_zero, args->unk5_zero, args->unk6, args->unk7,
|
||||
args->unk8);
|
||||
|
||||
dceInstance->bufferAttributes.pixelFormat = args->pixelFormat;
|
||||
dceInstance->bufferAttributes.tilingMode = args->tilingMode;
|
||||
dceInstance->bufferAttributes.pitch = args->pitch;
|
||||
dceInstance->bufferAttributes.width = args->width;
|
||||
dceInstance->bufferAttributes.height = args->height;
|
||||
return 0;
|
||||
device->bufferAttributes.pixelFormat = args->pixelFormat;
|
||||
device->bufferAttributes.tilingMode = args->tilingMode;
|
||||
device->bufferAttributes.pitch = args->pitch;
|
||||
device->bufferAttributes.width = args->width;
|
||||
device->bufferAttributes.height = args->height;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (request == 0xc0488204) {
|
||||
|
|
@ -217,13 +223,13 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
|
||||
rx::bridge.sendFlip(args->displayBufferIndex,
|
||||
/*args->flipMode,*/ args->flipArg);
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (request == 0x80088209) { // deallocate?
|
||||
auto arg = *reinterpret_cast<std::uint64_t *>(argp);
|
||||
ORBIS_LOG_ERROR("dce: 0x80088209", arg);
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
ORBIS_LOG_FATAL("Unhandled dce ioctl", request);
|
||||
|
|
@ -231,30 +237,37 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
|
||||
std::fflush(stdout);
|
||||
__builtin_trap();
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
static void *dce_instance_mmap(IoDeviceInstance *instance, void *address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset) {
|
||||
static orbis::ErrorCode dce_mmap(orbis::File *file, void **address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset,
|
||||
orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("dce mmap", address, size, offset);
|
||||
return rx::vm::map(address, size, prot, flags);
|
||||
auto result = rx::vm::map(*address, size, prot, flags);
|
||||
|
||||
if (result == (void *)-1) {
|
||||
return orbis::ErrorCode::INVAL; // TODO
|
||||
}
|
||||
|
||||
*address = result;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t dce_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<DceInstance>();
|
||||
newInstance->ioctl = dce_instance_ioctl;
|
||||
newInstance->mmap = dce_instance_mmap;
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = dce_ioctl,
|
||||
.mmap = dce_mmap,
|
||||
};
|
||||
|
||||
orbis::ErrorCode DceDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<DceFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createDceCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<DceDevice>();
|
||||
newDevice->open = dce_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
IoDevice *createDceCharacterDevice() { return orbis::knew<DceDevice>(); }
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
struct DipswDevice : public IoDevice {};
|
||||
struct DipswFile : public orbis::File {};
|
||||
|
||||
struct DipswInstance : public IoDeviceInstance {};
|
||||
|
||||
static std::int64_t dipsw_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
static orbis::ErrorCode dipsw_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
if (request == 0x40048806) { // is connected?
|
||||
ORBIS_LOG_ERROR("dipsw ioctl 0x40048806", argp);
|
||||
|
||||
*reinterpret_cast<std::uint32_t *>(argp) = 0;
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
// 0x40088808
|
||||
|
|
@ -22,7 +20,7 @@ static std::int64_t dipsw_instance_ioctl(IoDeviceInstance *instance,
|
|||
if (request == 0x40088808) {
|
||||
ORBIS_LOG_ERROR("dipsw ioctl 0x40088808", argp);
|
||||
*reinterpret_cast<std::uint32_t *>(argp) = 1;
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
// 0x8010880a
|
||||
|
|
@ -36,28 +34,27 @@ static std::int64_t dipsw_instance_ioctl(IoDeviceInstance *instance,
|
|||
|
||||
ORBIS_LOG_ERROR("dipsw ioctl 0x8010880a", args->address, args->size);
|
||||
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
ORBIS_LOG_FATAL("Unhandled dipsw ioctl", request);
|
||||
std::fflush(stdout);
|
||||
//__builtin_trap();
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t dipsw_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<DipswInstance>();
|
||||
newInstance->ioctl = dipsw_instance_ioctl;
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
}
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = dipsw_ioctl,
|
||||
};
|
||||
|
||||
IoDevice *createDipswCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<DipswDevice>();
|
||||
newDevice->open = dipsw_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
struct DipswDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override {
|
||||
auto newFile = orbis::knew<DipswFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
IoDevice *createDipswCharacterDevice() { return orbis::knew<DipswDevice>(); }
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include "orbis/utils/SharedMutex.hpp"
|
||||
#include "vm.hpp"
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <mutex>
|
||||
|
||||
struct DmemDevice : public IoDevice {
|
||||
orbis::shared_mutex mtx;
|
||||
int index;
|
||||
std::uint64_t nextOffset;
|
||||
std::uint64_t memBeginAddress;
|
||||
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
|
||||
struct DmemInstance : public IoDeviceInstance {};
|
||||
struct DmemFile : public orbis::File {};
|
||||
|
||||
struct AllocateDirectMemoryArgs {
|
||||
std::uint64_t searchStart;
|
||||
|
|
@ -25,20 +30,21 @@ static constexpr auto dmemSize = 4ul * 1024 * 1024 * 1024;
|
|||
// static const std::uint64_t nextOffset = 0;
|
||||
// static const std::uint64_t memBeginAddress = 0xfe0000000;
|
||||
|
||||
static std::int64_t dmem_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
static orbis::ErrorCode dmem_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
auto device = static_cast<DmemDevice *>(file->device.get());
|
||||
|
||||
auto device = static_cast<DmemDevice *>(instance->device.get());
|
||||
std::lock_guard lock(device->mtx);
|
||||
switch (request) {
|
||||
case 0x4008800a: // get size
|
||||
ORBIS_LOG_ERROR("dmem getTotalSize", device->index, argp);
|
||||
*(std::uint64_t *)argp = dmemSize;
|
||||
return 0;
|
||||
return {};
|
||||
|
||||
case 0xc0208016: // get avaiable size
|
||||
ORBIS_LOG_ERROR("dmem getAvaiableSize", device->index, argp);
|
||||
*(std::uint64_t *)argp = dmemSize - device->nextOffset;
|
||||
return 0;
|
||||
return {};
|
||||
|
||||
case 0xc0288001: { // sceKernelAllocateDirectMemory
|
||||
auto args = reinterpret_cast<AllocateDirectMemoryArgs *>(argp);
|
||||
|
|
@ -50,12 +56,12 @@ static std::int64_t dmem_instance_ioctl(IoDeviceInstance *instance,
|
|||
args->alignment, args->memoryType, alignedOffset);
|
||||
|
||||
if (alignedOffset + args->len > dmemSize) {
|
||||
return -1;
|
||||
return orbis::ErrorCode::NOMEM;
|
||||
}
|
||||
|
||||
args->searchStart = alignedOffset;
|
||||
device->nextOffset = alignedOffset + args->len;
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
case 0x80108002: { // sceKernelReleaseDirectMemory
|
||||
|
|
@ -70,48 +76,51 @@ static std::int64_t dmem_instance_ioctl(IoDeviceInstance *instance,
|
|||
args->size);
|
||||
// std::fflush(stdout);
|
||||
//__builtin_trap();
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
ORBIS_LOG_FATAL("Unhandled dmem ioctl", device->index, request);
|
||||
return 0;
|
||||
|
||||
std::fflush(stdout);
|
||||
__builtin_trap();
|
||||
return {};
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void *dmem_instance_mmap(IoDeviceInstance *instance, void *address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset) {
|
||||
auto device = static_cast<DmemDevice *>(instance->device.get());
|
||||
static orbis::ErrorCode dmem_mmap(orbis::File *file, void **address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset,
|
||||
orbis::Thread *thread) {
|
||||
auto device = static_cast<DmemDevice *>(file->device.get());
|
||||
auto target = device->memBeginAddress + offset;
|
||||
ORBIS_LOG_WARNING("dmem mmap", device->index, offset, target);
|
||||
|
||||
auto addr = rx::vm::map(reinterpret_cast<void *>(target), size, prot, flags);
|
||||
return addr;
|
||||
auto result =
|
||||
rx::vm::map(reinterpret_cast<void *>(target), size, prot, flags);
|
||||
|
||||
if (result == (void *)-1) {
|
||||
return orbis::ErrorCode::INVAL; // TODO
|
||||
}
|
||||
|
||||
*address = result;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t dmem_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<DmemInstance>();
|
||||
newInstance->ioctl = dmem_instance_ioctl;
|
||||
newInstance->mmap = dmem_instance_mmap;
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = dmem_ioctl,
|
||||
.mmap = dmem_mmap,
|
||||
};
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
orbis::ErrorCode DmemDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<DmemFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createDmemCharacterDevice(int index) {
|
||||
auto *newDevice = orbis::knew<DmemDevice>();
|
||||
newDevice->open = dmem_device_open;
|
||||
newDevice->index = index;
|
||||
newDevice->nextOffset = 0;
|
||||
newDevice->memBeginAddress = 0xf'e000'0000 + dmemSize * index;
|
||||
|
|
|
|||
|
|
@ -1,27 +1,21 @@
|
|||
#include "bridge.hpp"
|
||||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include <atomic>
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
// #include <rpcs4/bridge.hpp>
|
||||
#include "vm.hpp"
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <sys/mman.h>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
struct GcDevice : public IoDevice {};
|
||||
|
||||
struct GcInstance : public IoDeviceInstance {};
|
||||
|
||||
struct GcDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
struct GcFile : public orbis::File {};
|
||||
static std::uint64_t g_submitDoneFlag;
|
||||
|
||||
static std::int64_t gc_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
// 0xc00c8110
|
||||
// 0xc0848119
|
||||
|
||||
|
|
@ -30,7 +24,7 @@ static std::int64_t gc_instance_ioctl(IoDeviceInstance *instance,
|
|||
// TODO
|
||||
ORBIS_LOG_ERROR("gc ioctl 0xc008811b", *(std::uint64_t *)argp);
|
||||
*reinterpret_cast<void **>(argp) = &g_submitDoneFlag;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 0xc0108102: { // submit?
|
||||
struct Args {
|
||||
|
|
@ -44,7 +38,7 @@ static std::int64_t gc_instance_ioctl(IoDeviceInstance *instance,
|
|||
flockfile(stderr);
|
||||
ORBIS_LOG_ERROR("gc ioctl 0xc0108102", args->arg0, args->count, args->cmds);
|
||||
|
||||
for (int i = 0; i < args->count; ++i) {
|
||||
for (unsigned i = 0; i < args->count; ++i) {
|
||||
auto cmd = args->cmds + (i * 2);
|
||||
auto cmdId = cmd[0] & 0xffff'ffff;
|
||||
auto addressLoPart = cmd[0] >> 32;
|
||||
|
|
@ -95,7 +89,7 @@ static std::int64_t gc_instance_ioctl(IoDeviceInstance *instance,
|
|||
ORBIS_LOG_ERROR("gc ioctl 0xc020810c", args->arg0, args->count, args->cmds,
|
||||
args->arg3, args->arg4);
|
||||
|
||||
for (int i = 0; i < args->count; ++i) {
|
||||
for (unsigned i = 0; i < args->count; ++i) {
|
||||
auto cmd = args->cmds + (i * 2);
|
||||
auto cmdId = cmd[0] & 0xffff'ffff;
|
||||
auto addressLoPart = cmd[0] >> 32;
|
||||
|
|
@ -238,31 +232,36 @@ static std::int64_t gc_instance_ioctl(IoDeviceInstance *instance,
|
|||
__builtin_trap();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
static void *gc_instance_mmap(IoDeviceInstance *instance, void *address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset) {
|
||||
ORBIS_LOG_FATAL("Unhandled gc mmap", offset);
|
||||
static orbis::ErrorCode gc_mmap(orbis::File *file, void **address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset,
|
||||
orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("gc mmap", address, size, offset);
|
||||
auto result = rx::vm::map(*address, size, prot, flags);
|
||||
|
||||
return rx::vm::map(address, size, prot, flags);
|
||||
if (result == (void *)-1) {
|
||||
return orbis::ErrorCode::INVAL; // TODO
|
||||
}
|
||||
|
||||
*address = result;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t gc_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<GcInstance>();
|
||||
newInstance->ioctl = gc_instance_ioctl;
|
||||
newInstance->mmap = gc_instance_mmap;
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = gc_ioctl,
|
||||
.mmap = gc_mmap,
|
||||
};
|
||||
|
||||
orbis::ErrorCode GcDevice::open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<GcFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createGcCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<GcDevice>();
|
||||
newDevice->open = gc_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
IoDevice *createGcCharacterDevice() { return orbis::knew<GcDevice>(); }
|
||||
|
|
|
|||
|
|
@ -1,43 +1,34 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include "vm.hpp"
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
|
||||
struct HidDevice : public IoDevice {};
|
||||
struct HidInstance : public IoDeviceInstance {};
|
||||
struct HidDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
struct HidFile : public orbis::File {};
|
||||
|
||||
static std::int64_t hid_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
static orbis::ErrorCode hid_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("Unhandled hid ioctl", request);
|
||||
|
||||
// 0x800c4802
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
static void *hid_instance_mmap(IoDeviceInstance *instance, void *address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset) {
|
||||
ORBIS_LOG_FATAL("Unhandled hid mmap", offset);
|
||||
return rx::vm::map(address, size, prot, flags);
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = hid_ioctl,
|
||||
};
|
||||
|
||||
orbis::ErrorCode HidDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<HidFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t hid_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<HidInstance>();
|
||||
newInstance->ioctl = hid_instance_ioctl;
|
||||
newInstance->mmap = hid_instance_mmap;
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
}
|
||||
|
||||
IoDevice *createHidCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<HidDevice>();
|
||||
newDevice->open = hid_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
IoDevice *createHidCharacterDevice() { return orbis::knew<HidDevice>(); }
|
||||
|
|
|
|||
|
|
@ -1,33 +1,34 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
struct Hmd3daDevice : public IoDevice {};
|
||||
|
||||
struct Hmd3daInstance : public IoDeviceInstance {};
|
||||
|
||||
static std::int64_t hmd_3da_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
struct Hmd3daDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
struct Hmd3daFile : public orbis::File {};
|
||||
|
||||
static orbis::ErrorCode hmd_3da_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("Unhandled hmd_3da ioctl", request);
|
||||
return -1;
|
||||
|
||||
// 0x800c4802
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t hmd_3da_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<Hmd3daInstance>();
|
||||
newInstance->ioctl = hmd_3da_instance_ioctl;
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = hmd_3da_ioctl,
|
||||
};
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
orbis::ErrorCode Hmd3daDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<Hmd3daFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createHmd3daCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<Hmd3daDevice>();
|
||||
newDevice->open = hmd_3da_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
IoDevice *createHmd3daCharacterDevice() { return orbis::knew<Hmd3daDevice>(); }
|
||||
|
|
|
|||
|
|
@ -1,34 +1,33 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
struct HmdCmdDevice : public IoDevice {};
|
||||
|
||||
struct HmdCmdInstance : public IoDeviceInstance {};
|
||||
|
||||
static std::int64_t hmd_cmd_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
struct HmdCmdDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
struct HmdCmdFile : public orbis::File {};
|
||||
|
||||
static orbis::ErrorCode hmd_cmd_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("Unhandled hmd_cmd ioctl", request);
|
||||
return -1;
|
||||
|
||||
// 0x800c4802
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t hmd_cmd_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<HmdCmdInstance>();
|
||||
newInstance->ioctl = hmd_cmd_instance_ioctl;
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = hmd_cmd_ioctl,
|
||||
};
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
orbis::ErrorCode HmdCmdDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<HmdCmdFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createHmdCmdCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<HmdCmdDevice>();
|
||||
newDevice->open = hmd_cmd_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
IoDevice *createHmdCmdCharacterDevice() { return orbis::knew<HmdCmdDevice>(); }
|
||||
|
|
|
|||
|
|
@ -2,44 +2,51 @@
|
|||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include "vm.hpp"
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
|
||||
struct HmdMmapDevice : public IoDevice {};
|
||||
|
||||
struct HmdMmapInstance : public IoDeviceInstance {};
|
||||
|
||||
static std::int64_t hmd_mmap_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
struct HmdMmapDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
struct HmdMmapFile : public orbis::File {};
|
||||
|
||||
static orbis::ErrorCode hmd_mmap_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("Unhandled hmd_mmap ioctl", request);
|
||||
std::fflush(stdout);
|
||||
__builtin_trap();
|
||||
return -1;
|
||||
|
||||
// 0x800c4802
|
||||
return {};
|
||||
}
|
||||
|
||||
static void *hmd_mmap_instance_mmap(IoDeviceInstance *instance, void *address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset) {
|
||||
ORBIS_LOG_FATAL("Unhandled hmd_mmap mmap", offset);
|
||||
return rx::vm::map(address, size, prot, flags);
|
||||
static orbis::ErrorCode hmd_mmap_mmap(orbis::File *file, void **address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset,
|
||||
orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("hmd_mmap mmap", address, size, offset);
|
||||
auto result = rx::vm::map(*address, size, prot, flags);
|
||||
|
||||
if (result == (void *)-1) {
|
||||
return orbis::ErrorCode::INVAL; // TODO
|
||||
}
|
||||
|
||||
*address = result;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t hmd_mmap_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<HmdMmapInstance>();
|
||||
newInstance->ioctl = hmd_mmap_instance_ioctl;
|
||||
newInstance->mmap = hmd_mmap_instance_mmap;
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = hmd_mmap_ioctl,
|
||||
.mmap = hmd_mmap_mmap,
|
||||
};
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
orbis::ErrorCode HmdMmapDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<HmdMmapFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createHmdMmapCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<HmdMmapDevice>();
|
||||
newDevice->open = hmd_mmap_device_open;
|
||||
return newDevice;
|
||||
return orbis::knew<HmdMmapDevice>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,36 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
struct HmdSnsrDevice : public IoDevice {};
|
||||
struct HmdSnsrDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
struct HmdSnsrFile : public orbis::File {};
|
||||
|
||||
struct HmdSnsrInstance : public IoDeviceInstance {};
|
||||
|
||||
static std::int64_t smd_snr_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
static orbis::ErrorCode hmd_snsr_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("Unhandled hmd_snsr ioctl", request);
|
||||
return -1;
|
||||
|
||||
// 0x800c4802
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t smd_snr_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<HmdSnsrInstance>();
|
||||
newInstance->ioctl = smd_snr_instance_ioctl;
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = hmd_snsr_ioctl,
|
||||
};
|
||||
|
||||
orbis::ErrorCode HmdSnsrDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<HmdSnsrFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createHmdSnsrCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<HmdSnsrDevice>();
|
||||
newDevice->open = smd_snr_device_open;
|
||||
return newDevice;
|
||||
return orbis::knew<HmdSnsrDevice>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,31 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/uio.hpp"
|
||||
|
||||
struct NullDevice : public IoDevice {};
|
||||
struct NullDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
struct NullFile : public orbis::File {};
|
||||
|
||||
struct NullInstance : public IoDeviceInstance {};
|
||||
|
||||
static std::int64_t null_instance_write(IoDeviceInstance *instance,
|
||||
const void *data, std::uint64_t size) {
|
||||
return size;
|
||||
static orbis::ErrorCode null_write(orbis::File *file, orbis::Uio *uio,
|
||||
orbis::Thread *) {
|
||||
uio->resid = 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t null_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<NullInstance>();
|
||||
newInstance->write = null_instance_write;
|
||||
static const orbis::FileOps ops = {
|
||||
.write = null_write,
|
||||
};
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
orbis::ErrorCode NullDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<NullFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createNullCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<NullDevice>();
|
||||
newDevice->open = null_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
IoDevice *createNullCharacterDevice() { return orbis::knew<NullDevice>(); }
|
||||
|
|
|
|||
|
|
@ -2,40 +2,49 @@
|
|||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include "vm.hpp"
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
|
||||
struct RngDevice : public IoDevice {};
|
||||
struct RngInstance : public IoDeviceInstance {};
|
||||
struct RngDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
struct RngFile : public orbis::File {};
|
||||
|
||||
static std::int64_t rng_instance_ioctl(IoDeviceInstance *instance,
|
||||
std::uint64_t request, void *argp) {
|
||||
static orbis::ErrorCode rng_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("Unhandled rng ioctl", request);
|
||||
return 0;
|
||||
|
||||
// 0x800c4802
|
||||
return {};
|
||||
}
|
||||
|
||||
static void *rng_instance_mmap(IoDeviceInstance *instance, void *address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset) {
|
||||
ORBIS_LOG_FATAL("Unhandled rng mmap", offset);
|
||||
return rx::vm::map(address, size, prot, flags);
|
||||
static orbis::ErrorCode rng_mmap(orbis::File *file, void **address,
|
||||
std::uint64_t size, std::int32_t prot,
|
||||
std::int32_t flags, std::int64_t offset,
|
||||
orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("rng mmap", address, size, offset);
|
||||
auto result = rx::vm::map(*address, size, prot, flags);
|
||||
|
||||
if (result == (void *)-1) {
|
||||
return orbis::ErrorCode::INVAL; // TODO
|
||||
}
|
||||
|
||||
*address = result;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t rng_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<RngInstance>();
|
||||
newInstance->ioctl = rng_instance_ioctl;
|
||||
newInstance->mmap = rng_instance_mmap;
|
||||
static const orbis::FileOps ops = {
|
||||
.ioctl = rng_ioctl,
|
||||
.mmap = rng_mmap,
|
||||
};
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
orbis::ErrorCode RngDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<RngFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createRngCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<RngDevice>();
|
||||
newDevice->open = rng_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
IoDevice *createRngCharacterDevice() { return orbis::knew<RngDevice>(); }
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include <fstream>
|
||||
|
||||
struct StderrInstance : public IoDeviceInstance {};
|
||||
|
||||
struct StderrDevice : public IoDevice {
|
||||
StderrInstance *instance = nullptr;
|
||||
};
|
||||
|
||||
static std::int64_t stderr_instance_write(IoDeviceInstance *instance,
|
||||
const void *data,
|
||||
std::uint64_t size) {
|
||||
static const bool istty = isatty(fileno(stderr));
|
||||
if (size && istty)
|
||||
std::fprintf(stderr, "\e[0;35m");
|
||||
auto result = std::fwrite(data, 1, size, stderr);
|
||||
if (size && istty)
|
||||
std::fprintf(stderr, "\e[0m");
|
||||
std::fflush(stderr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::int64_t stderr_instance_close(IoDeviceInstance *instance) {
|
||||
instance->device->decRef();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::int32_t stderr_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto stderrDevice = static_cast<StderrDevice *>(device);
|
||||
if (stderrDevice->instance == nullptr) {
|
||||
auto *newInstance = orbis::knew<StderrInstance>();
|
||||
newInstance->write = stderr_instance_write;
|
||||
newInstance->close = stderr_instance_close;
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
|
||||
*instance = newInstance;
|
||||
} else {
|
||||
device->incRef();
|
||||
|
||||
*instance = stderrDevice->instance;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
IoDevice *createStderrCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<StderrDevice>();
|
||||
newDevice->open = stderr_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
|
||||
struct StdinDevice : public IoDevice {};
|
||||
|
||||
struct StdinInstance : public IoDeviceInstance {};
|
||||
|
||||
static std::int64_t stdin_instance_read(IoDeviceInstance *instance, void *data,
|
||||
std::uint64_t size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static std::int32_t open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<StdinInstance>();
|
||||
newInstance->read = stdin_instance_read;
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
}
|
||||
|
||||
IoDevice *createStdinCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<StdinDevice>();
|
||||
newDevice->open = open;
|
||||
return newDevice;
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
struct StdoutInstance : public IoDeviceInstance {};
|
||||
|
||||
struct StdoutDevice : public IoDevice {
|
||||
StdoutInstance *instance = nullptr;
|
||||
};
|
||||
|
||||
static std::int64_t stdout_instance_write(IoDeviceInstance *instance,
|
||||
const void *data,
|
||||
std::uint64_t size) {
|
||||
static const bool istty = isatty(fileno(stdout));
|
||||
if (size && istty)
|
||||
std::fprintf(stdout, "\e[30;1m");
|
||||
auto result = std::fwrite(data, 1, size, stdout);
|
||||
if (size && istty)
|
||||
std::fprintf(stdout, "\e[0m");
|
||||
std::fflush(stdout);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::int64_t stdout_instance_close(IoDeviceInstance *instance) {
|
||||
instance->device->decRef();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::int32_t stdout_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto stdoutDevice = static_cast<StdoutDevice *>(device);
|
||||
if (stdoutDevice->instance == nullptr) {
|
||||
auto *newInstance = orbis::knew<StdoutInstance>();
|
||||
newInstance->write = stdout_instance_write;
|
||||
newInstance->close = stdout_instance_close;
|
||||
io_device_instance_init(device, newInstance);
|
||||
|
||||
*instance = newInstance;
|
||||
} else {
|
||||
device->incRef();
|
||||
*instance = stdoutDevice->instance;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
IoDevice *createStdoutCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<StdoutDevice>();
|
||||
newDevice->open = stdout_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
|
|
@ -1,31 +1,37 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/uio.hpp"
|
||||
#include <cstring>
|
||||
#include <span>
|
||||
|
||||
struct ZeroDevice : public IoDevice {};
|
||||
struct ZeroDevice : public IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode) override;
|
||||
};
|
||||
struct ZeroFile : public orbis::File {};
|
||||
|
||||
struct ZeroInstance : public IoDeviceInstance {};
|
||||
|
||||
static std::int64_t zero_device_read(IoDeviceInstance *instance, void *data,
|
||||
std::uint64_t size) {
|
||||
std::memset(data, 0, size);
|
||||
return size;
|
||||
static orbis::ErrorCode zero_read(orbis::File *file, orbis::Uio *uio,
|
||||
orbis::Thread *) {
|
||||
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
|
||||
std::memset(entry.base, 0, entry.len);
|
||||
uio->offset += entry.len;
|
||||
}
|
||||
uio->resid = 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::int32_t zero_device_open(IoDevice *device,
|
||||
orbis::Ref<IoDeviceInstance> *instance,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto *newInstance = orbis::knew<ZeroInstance>();
|
||||
newInstance->read = zero_device_read;
|
||||
static const orbis::FileOps ops = {
|
||||
.read = zero_read,
|
||||
};
|
||||
|
||||
io_device_instance_init(device, newInstance);
|
||||
*instance = newInstance;
|
||||
return 0;
|
||||
orbis::ErrorCode ZeroDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode) {
|
||||
auto newFile = orbis::knew<ZeroFile>();
|
||||
newFile->device = this;
|
||||
newFile->ops = &ops;
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createZeroCharacterDevice() {
|
||||
auto *newDevice = orbis::knew<ZeroDevice>();
|
||||
newDevice->open = zero_device_open;
|
||||
return newDevice;
|
||||
}
|
||||
IoDevice *createZeroCharacterDevice() { return orbis::knew<ZeroDevice>(); }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/module/Module.hpp"
|
||||
#include "orbis/stat.hpp"
|
||||
#include "orbis/uio.hpp"
|
||||
#include "vfs.hpp"
|
||||
#include "vm.hpp"
|
||||
#include <crypto/sha1.h>
|
||||
|
|
@ -838,38 +840,56 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
|
|||
}
|
||||
|
||||
Ref<orbis::Module> rx::linker::loadModuleFile(std::string_view path,
|
||||
orbis::Process *process) {
|
||||
orbis::Thread *thread) {
|
||||
if (!path.contains('/')) {
|
||||
return loadModuleByName(path, process);
|
||||
return loadModuleByName(path, thread);
|
||||
}
|
||||
|
||||
orbis::Ref<IoDeviceInstance> instance;
|
||||
orbis::Ref<orbis::File> instance;
|
||||
if (vfs::open(path, kOpenFlagReadOnly, 0, &instance).isError()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto len = instance->lseek(instance.get(), 0, SEEK_END);
|
||||
instance->lseek(instance.get(), 0, SEEK_SET);
|
||||
orbis::Stat fileStat;
|
||||
if (instance->ops->stat(instance.get(), &fileStat, nullptr) !=
|
||||
orbis::ErrorCode{}) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto len = fileStat.size;
|
||||
|
||||
std::vector<std::byte> image(len);
|
||||
auto ptr = image.data();
|
||||
auto endPtr = ptr + image.size();
|
||||
orbis::IoVec ioVec{
|
||||
.base = ptr,
|
||||
.len = static_cast<std::uint64_t>(len),
|
||||
};
|
||||
orbis::Uio io{
|
||||
.offset = 0,
|
||||
.iov = &ioVec,
|
||||
.iovcnt = 1,
|
||||
.resid = 0,
|
||||
.segflg = orbis::UioSeg::SysSpace,
|
||||
.rw = orbis::UioRw::Read,
|
||||
.td = thread,
|
||||
};
|
||||
|
||||
while (ptr != endPtr) {
|
||||
auto result = instance->read(instance.get(), ptr, endPtr - ptr);
|
||||
if (result < 0) {
|
||||
while (io.offset < image.size()) {
|
||||
ioVec = {
|
||||
.base = ptr + io.offset,
|
||||
.len = image.size() - io.offset,
|
||||
};
|
||||
auto result = instance->ops->read(instance.get(), &io, thread);
|
||||
if (result != orbis::ErrorCode{}) {
|
||||
std::fprintf(stderr, "Module file reading error\n");
|
||||
std::abort();
|
||||
}
|
||||
ptr += result;
|
||||
}
|
||||
|
||||
instance->close(instance.get());
|
||||
|
||||
return loadModule(image, process);
|
||||
return loadModule(image, thread->tproc);
|
||||
}
|
||||
|
||||
static Ref<orbis::Module> createSceFreeTypeFull(orbis::Process *process) {
|
||||
static Ref<orbis::Module> createSceFreeTypeFull(orbis::Thread *thread) {
|
||||
auto result = orbis::knew<orbis::Module>();
|
||||
|
||||
std::strncpy(result->soName, "libSceFreeTypeFull.prx",
|
||||
|
|
@ -888,7 +908,7 @@ static Ref<orbis::Module> createSceFreeTypeFull(orbis::Process *process) {
|
|||
}
|
||||
|
||||
for (auto needed : result->needed) {
|
||||
auto neededMod = rx::linker::loadModuleByName(needed, process);
|
||||
auto neededMod = rx::linker::loadModuleByName(needed, thread);
|
||||
|
||||
if (neededMod == nullptr) {
|
||||
std::fprintf(stderr, "Failed to load needed '%s' for FreeType\n",
|
||||
|
|
@ -903,20 +923,20 @@ static Ref<orbis::Module> createSceFreeTypeFull(orbis::Process *process) {
|
|||
result->initProc = reinterpret_cast<void *>(+[] {});
|
||||
result->finiProc = reinterpret_cast<void *>(+[] {});
|
||||
|
||||
result->proc = process;
|
||||
result->proc = thread->tproc;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Ref<orbis::Module> rx::linker::loadModuleByName(std::string_view name,
|
||||
orbis::Process *process) {
|
||||
orbis::Thread *thread) {
|
||||
if (name.ends_with(".prx")) {
|
||||
name.remove_suffix(4);
|
||||
}
|
||||
|
||||
if (auto it = g_moduleOverrideTable.find(name);
|
||||
it != g_moduleOverrideTable.end()) {
|
||||
return loadModuleFile(it->second.c_str(), process);
|
||||
return loadModuleFile(it->second.c_str(), thread);
|
||||
}
|
||||
|
||||
if (name == "libSceAbstractTwitch") {
|
||||
|
|
@ -924,14 +944,14 @@ Ref<orbis::Module> rx::linker::loadModuleByName(std::string_view name,
|
|||
}
|
||||
|
||||
if (name == "libSceFreeTypeFull") {
|
||||
return createSceFreeTypeFull(process);
|
||||
return createSceFreeTypeFull(thread);
|
||||
}
|
||||
|
||||
{
|
||||
std::string filePath = "/app0/sce_module/";
|
||||
filePath += name;
|
||||
filePath += ".elf";
|
||||
if (auto result = rx::linker::loadModuleFile(filePath.c_str(), process)) {
|
||||
if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -941,7 +961,7 @@ Ref<orbis::Module> rx::linker::loadModuleByName(std::string_view name,
|
|||
filePath += name;
|
||||
filePath += ".sprx";
|
||||
|
||||
if (auto result = rx::linker::loadModuleFile(filePath.c_str(), process)) {
|
||||
if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ void override(std::string originalModuleName,
|
|||
orbis::Ref<orbis::Module> loadModule(std::span<std::byte> image,
|
||||
orbis::Process *process);
|
||||
orbis::Ref<orbis::Module> loadModuleFile(std::string_view path,
|
||||
orbis::Process *process);
|
||||
orbis::Thread *thread);
|
||||
orbis::Ref<orbis::Module> loadModuleByName(std::string_view name,
|
||||
orbis::Process *process);
|
||||
orbis::Thread *thread);
|
||||
} // namespace rx::linker
|
||||
|
|
|
|||
|
|
@ -290,17 +290,9 @@ static void onSysExit(orbis::Thread *thread, int id, uint64_t *args,
|
|||
funlockfile(stderr);
|
||||
}
|
||||
|
||||
static int ps4Exec(orbis::Process *mainProcess,
|
||||
static int ps4Exec(orbis::Thread *mainThread,
|
||||
orbis::utils::Ref<orbis::Module> executableModule,
|
||||
std::span<const char *> argv, std::span<const char *> envp) {
|
||||
mainProcess->sysent = &orbis::ps4_sysvec;
|
||||
mainProcess->ops = &rx::procOpsTable;
|
||||
|
||||
auto [baseId, mainThread] = mainProcess->threadsMap.emplace();
|
||||
mainThread->tproc = mainProcess;
|
||||
mainThread->tid = mainProcess->pid + baseId;
|
||||
mainThread->state = orbis::ThreadState::RUNNING;
|
||||
|
||||
const auto stackEndAddress = 0x7'ffff'c000ull;
|
||||
const auto stackSize = 0x40000 * 16;
|
||||
auto stackStartAddress = stackEndAddress - stackSize;
|
||||
|
|
@ -316,9 +308,9 @@ static int ps4Exec(orbis::Process *mainProcess,
|
|||
rx::vfs::mount("/dev/dmem0", createDmemCharacterDevice(0));
|
||||
rx::vfs::mount("/dev/dmem1", createDmemCharacterDevice(1));
|
||||
rx::vfs::mount("/dev/dmem2", createDmemCharacterDevice(2));
|
||||
rx::vfs::mount("/dev/stdout", createStdoutCharacterDevice());
|
||||
rx::vfs::mount("/dev/stderr", createStderrCharacterDevice());
|
||||
rx::vfs::mount("/dev/stdin", createStdinCharacterDevice());
|
||||
rx::vfs::mount("/dev/stdout", createFdWrapDevice(STDOUT_FILENO));
|
||||
rx::vfs::mount("/dev/stderr", createFdWrapDevice(STDERR_FILENO));
|
||||
rx::vfs::mount("/dev/stdin", createFdWrapDevice(STDIN_FILENO));
|
||||
rx::vfs::mount("/dev/zero", createZeroCharacterDevice());
|
||||
rx::vfs::mount("/dev/null", createNullCharacterDevice());
|
||||
rx::vfs::mount("/dev/dipsw", createDipswCharacterDevice());
|
||||
|
|
@ -332,22 +324,29 @@ static int ps4Exec(orbis::Process *mainProcess,
|
|||
rx::vfs::mount("/dev/rng", createRngCharacterDevice());
|
||||
rx::vfs::mount("/dev/ajm", createAjmCharacterDevice());
|
||||
|
||||
rx::procOpsTable.open(mainThread, "/dev/stdin", 0, 0);
|
||||
rx::procOpsTable.open(mainThread, "/dev/stdout", 0, 0);
|
||||
rx::procOpsTable.open(mainThread, "/dev/stderr", 0, 0);
|
||||
orbis::Ref<orbis::File> stdinFile;
|
||||
orbis::Ref<orbis::File> stdoutFile;
|
||||
orbis::Ref<orbis::File> stderrFile;
|
||||
rx::procOpsTable.open(mainThread, "/dev/stdin", 0, 0, &stdinFile);
|
||||
rx::procOpsTable.open(mainThread, "/dev/stdout", 0, 0, &stdoutFile);
|
||||
rx::procOpsTable.open(mainThread, "/dev/stderr", 0, 0, &stderrFile);
|
||||
|
||||
mainThread->tproc->fileDescriptors.insert(stdinFile);
|
||||
mainThread->tproc->fileDescriptors.insert(stdoutFile);
|
||||
mainThread->tproc->fileDescriptors.insert(stderrFile);
|
||||
|
||||
std::vector<std::uint64_t> argvOffsets;
|
||||
std::vector<std::uint64_t> envpOffsets;
|
||||
|
||||
auto libkernel = rx::linker::loadModuleFile(
|
||||
"/system/common/lib/libkernel_sys.sprx", mainProcess);
|
||||
"/system/common/lib/libkernel_sys.sprx", mainThread);
|
||||
|
||||
if (libkernel == nullptr) {
|
||||
std::fprintf(stderr, "libkernel not found\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
libkernel->id = mainProcess->modulesMap.insert(libkernel);
|
||||
libkernel->id = mainThread->tproc->modulesMap.insert(libkernel);
|
||||
|
||||
// *reinterpret_cast<std::uint32_t *>(
|
||||
// reinterpret_cast<std::byte *>(libkernel->base) + 0x6c2e4) = ~0;
|
||||
|
|
@ -562,20 +561,6 @@ int main(int argc, const char *argv[]) {
|
|||
// rx::vm::printHostStats();
|
||||
auto initProcess = orbis::g_context.createProcess(10);
|
||||
pthread_setname_np(pthread_self(), "10.MAINTHREAD");
|
||||
initProcess->sysent = &orbis::ps4_sysvec;
|
||||
initProcess->onSysEnter = onSysEnter;
|
||||
initProcess->onSysExit = onSysExit;
|
||||
auto executableModule =
|
||||
rx::linker::loadModuleFile(argv[argIndex], initProcess);
|
||||
|
||||
if (executableModule == nullptr) {
|
||||
std::fprintf(stderr, "Failed to open '%s'\n", argv[argIndex]);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
executableModule->id = initProcess->modulesMap.insert(executableModule);
|
||||
initProcess->processParam = executableModule->processParam;
|
||||
initProcess->processParamSize = executableModule->processParamSize;
|
||||
|
||||
std::thread{[] {
|
||||
pthread_setname_np(pthread_self(), "Bridge");
|
||||
|
|
@ -641,9 +626,31 @@ int main(int argc, const char *argv[]) {
|
|||
|
||||
int status = 0;
|
||||
|
||||
initProcess->sysent = &orbis::ps4_sysvec;
|
||||
initProcess->onSysEnter = onSysEnter;
|
||||
initProcess->onSysExit = onSysExit;
|
||||
initProcess->ops = &rx::procOpsTable;
|
||||
|
||||
auto [baseId, mainThread] = initProcess->threadsMap.emplace();
|
||||
mainThread->tproc = initProcess;
|
||||
mainThread->tid = initProcess->pid + baseId;
|
||||
mainThread->state = orbis::ThreadState::RUNNING;
|
||||
|
||||
auto executableModule =
|
||||
rx::linker::loadModuleFile(argv[argIndex], mainThread);
|
||||
|
||||
if (executableModule == nullptr) {
|
||||
std::fprintf(stderr, "Failed to open '%s'\n", argv[argIndex]);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
executableModule->id = initProcess->modulesMap.insert(executableModule);
|
||||
initProcess->processParam = executableModule->processParam;
|
||||
initProcess->processParamSize = executableModule->processParamSize;
|
||||
|
||||
if (executableModule->type == rx::linker::kElfTypeSceDynExec ||
|
||||
executableModule->type == rx::linker::kElfTypeSceExec) {
|
||||
status = ps4Exec(initProcess, std::move(executableModule),
|
||||
status = ps4Exec(mainThread, std::move(executableModule),
|
||||
std::span(argv + argIndex, argc - argIndex),
|
||||
std::span<const char *>());
|
||||
} else {
|
||||
|
|
|
|||
326
rpcsx-os/ops.cpp
326
rpcsx-os/ops.cpp
|
|
@ -40,7 +40,7 @@ loadPrx(orbis::Thread *thread, std::string_view name, bool relocate,
|
|||
return {{}, it->second};
|
||||
}
|
||||
|
||||
auto module = rx::linker::loadModuleFile(name, thread->tproc);
|
||||
auto module = rx::linker::loadModuleFile(name, thread);
|
||||
|
||||
if (module == nullptr) {
|
||||
if (!expectedName.empty()) {
|
||||
|
|
@ -138,30 +138,35 @@ loadPrx(orbis::Thread *thread, std::string_view path, bool relocate) {
|
|||
orbis::SysResult mmap(orbis::Thread *thread, orbis::caddr_t addr,
|
||||
orbis::size_t len, orbis::sint prot, orbis::sint flags,
|
||||
orbis::sint fd, orbis::off_t pos) {
|
||||
auto result = (void *)-1;
|
||||
if (fd == -1) {
|
||||
result = rx::vm::map(addr, len, prot, flags);
|
||||
} else {
|
||||
Ref<IoDeviceInstance> handle =
|
||||
static_cast<IoDeviceInstance *>(thread->tproc->fileDescriptors.get(fd));
|
||||
if (handle == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
auto result = rx::vm::map(addr, len, prot, flags);
|
||||
if (result == (void *)-1) {
|
||||
return ErrorCode::NOMEM;
|
||||
}
|
||||
|
||||
if (handle->mmap != nullptr) {
|
||||
result = handle->mmap(handle.get(), addr, len, prot, flags, pos);
|
||||
} else {
|
||||
ORBIS_LOG_FATAL("unimplemented mmap", fd, (void *)addr, len, prot, flags,
|
||||
pos);
|
||||
result = rx::vm::map(addr, len, prot, flags);
|
||||
}
|
||||
thread->retval[0] = reinterpret_cast<std::uint64_t>(result);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (result == (void *)-1) {
|
||||
return ErrorCode::NOMEM;
|
||||
auto file = thread->tproc->fileDescriptors.get(fd);
|
||||
if (file == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
thread->retval[0] = reinterpret_cast<std::uint64_t>(result);
|
||||
if (file->ops->mmap == nullptr) {
|
||||
ORBIS_LOG_FATAL("unimplemented mmap", fd, (void *)addr, len, prot, flags,
|
||||
pos);
|
||||
return mmap(thread, addr, len, prot, flags, -1, 0);
|
||||
}
|
||||
|
||||
void *maddr = addr;
|
||||
auto result = file->ops->mmap(file, &maddr, len, prot, flags, pos, thread);
|
||||
|
||||
if (result != ErrorCode{}) {
|
||||
return result;
|
||||
}
|
||||
|
||||
thread->retval[0] = reinterpret_cast<std::uint64_t>(maddr);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
@ -225,281 +230,15 @@ orbis::SysResult virtual_query(orbis::Thread *thread,
|
|||
}
|
||||
|
||||
orbis::SysResult open(orbis::Thread *thread, orbis::ptr<const char> path,
|
||||
orbis::sint flags, orbis::sint mode) {
|
||||
orbis::Ref<IoDeviceInstance> instance;
|
||||
auto result = rx::vfs::open(path, flags, mode, &instance);
|
||||
if (result.isError()) {
|
||||
ORBIS_LOG_WARNING("Failed to open file", path, result.value());
|
||||
thread->where();
|
||||
return result;
|
||||
}
|
||||
|
||||
auto fd = thread->tproc->fileDescriptors.insert(instance);
|
||||
thread->retval[0] = fd;
|
||||
ORBIS_LOG_WARNING("File opened", path, fd);
|
||||
return {};
|
||||
orbis::sint flags, orbis::sint mode,
|
||||
orbis::Ref<orbis::File> *file) {
|
||||
return rx::vfs::open(path, flags, mode, file);
|
||||
}
|
||||
|
||||
orbis::SysResult socket(orbis::Thread *thread, orbis::ptr<const char> name,
|
||||
orbis::sint domain, orbis::sint type,
|
||||
orbis::sint protocol) {
|
||||
orbis::Ref<IoDeviceInstance> instance;
|
||||
auto error = createSocket(name, domain, type, protocol, &instance);
|
||||
if (error != ErrorCode{}) {
|
||||
ORBIS_LOG_WARNING("Failed to open socket", name, int(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
auto fd = thread->tproc->fileDescriptors.insert(instance);
|
||||
thread->retval[0] = fd;
|
||||
ORBIS_LOG_WARNING("Socket opened", name, fd);
|
||||
return {};
|
||||
}
|
||||
|
||||
orbis::SysResult close(orbis::Thread *thread, orbis::sint fd) {
|
||||
if (fd == 0) {
|
||||
return {};
|
||||
}
|
||||
if (!thread->tproc->fileDescriptors.close(fd)) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
ORBIS_LOG_WARNING("fd closed", fd);
|
||||
return {};
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
#define IOCPARM_SHIFT 13 /* number of bits for ioctl size */
|
||||
#define IOCPARM_MASK ((1 << IOCPARM_SHIFT) - 1) /* parameter length mask */
|
||||
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
|
||||
#define IOCBASECMD(x) ((x) & ~(IOCPARM_MASK << 16))
|
||||
#define IOCGROUP(x) (((x) >> 8) & 0xff)
|
||||
|
||||
#define IOCPARM_MAX (1 << IOCPARM_SHIFT) /* max size of ioctl */
|
||||
#define IOC_VOID 0x20000000 /* no parameters */
|
||||
#define IOC_OUT 0x40000000 /* copy out parameters */
|
||||
#define IOC_IN 0x80000000 /* copy in parameters */
|
||||
#define IOC_INOUT (IOC_IN | IOC_OUT)
|
||||
#define IOC_DIRMASK (IOC_VOID | IOC_OUT | IOC_IN)
|
||||
|
||||
#define _IOC(inout, group, num, len) \
|
||||
((unsigned long)((inout) | (((len) & IOCPARM_MASK) << 16) | ((group) << 8) | \
|
||||
(num)))
|
||||
#define _IO(g, n) _IOC(IOC_VOID, (g), (n), 0)
|
||||
#define _IOWINT(g, n) _IOC(IOC_VOID, (g), (n), sizeof(int))
|
||||
#define _IOR(g, n, t) _IOC(IOC_OUT, (g), (n), sizeof(t))
|
||||
#define _IOW(g, n, t) _IOC(IOC_IN, (g), (n), sizeof(t))
|
||||
/* this should be _IORW, but stdio got there first */
|
||||
#define _IOWR(g, n, t) _IOC(IOC_INOUT, (g), (n), sizeof(t))
|
||||
// clang-format on
|
||||
|
||||
static std::string iocGroupToString(unsigned iocGroup) {
|
||||
if (iocGroup >= 128) {
|
||||
const char *sceGroups[] = {
|
||||
"DEV",
|
||||
"DMEM",
|
||||
"GC",
|
||||
"DCE",
|
||||
"UVD",
|
||||
"VCE",
|
||||
"DBGGC",
|
||||
"TWSI",
|
||||
"MDBG",
|
||||
"DEVENV",
|
||||
"AJM",
|
||||
"TRACE",
|
||||
"IBS",
|
||||
"MBUS",
|
||||
"HDMI",
|
||||
"CAMERA",
|
||||
"FAN",
|
||||
"THERMAL",
|
||||
"PFS",
|
||||
"ICC_CONFIG",
|
||||
"IPC",
|
||||
"IOSCHED",
|
||||
"ICC_INDICATOR",
|
||||
"EXFATFS",
|
||||
"ICC_NVS",
|
||||
"DVE",
|
||||
"ICC_POWER",
|
||||
"AV_CONTROL",
|
||||
"ICC_SC_CONFIGURATION",
|
||||
"ICC_DEVICE_POWER",
|
||||
"SSHOT",
|
||||
"DCE_SCANIN",
|
||||
"FSCTRL",
|
||||
"HMD",
|
||||
"SHM",
|
||||
"PHYSHM",
|
||||
"HMDDFU",
|
||||
"BLUETOOTH_HID",
|
||||
"SBI",
|
||||
"S3DA",
|
||||
"SPM",
|
||||
"BLOCKPOOL",
|
||||
"SDK_EVENTLOG",
|
||||
};
|
||||
|
||||
if (iocGroup - 127 >= std::size(sceGroups)) {
|
||||
return "'?'";
|
||||
}
|
||||
|
||||
return sceGroups[iocGroup - 127];
|
||||
}
|
||||
|
||||
if (isprint(iocGroup)) {
|
||||
return "'" + std::string(1, (char)iocGroup) + "'";
|
||||
}
|
||||
|
||||
return "'?'";
|
||||
}
|
||||
|
||||
static void printIoctl(unsigned long arg) {
|
||||
std::printf("0x%lx { IO%s%s %lu(%s), %lu, %lu }\n", arg,
|
||||
arg & IOC_OUT ? "R" : "", arg & IOC_IN ? "W" : "", IOCGROUP(arg),
|
||||
iocGroupToString(IOCGROUP(arg)).c_str(), arg & 0xFF,
|
||||
IOCPARM_LEN(arg));
|
||||
}
|
||||
|
||||
static void ioctlToStream(std::ostream &stream, unsigned long arg) {
|
||||
stream << "0x" << std::hex << arg << " { IO";
|
||||
|
||||
if ((arg & IOC_OUT) != 0) {
|
||||
stream << 'R';
|
||||
}
|
||||
|
||||
if ((arg & IOC_IN) != 0) {
|
||||
stream << 'W';
|
||||
}
|
||||
if ((arg & IOC_VOID) != 0) {
|
||||
stream << 'i';
|
||||
}
|
||||
|
||||
stream << " 0x" << IOCGROUP(arg);
|
||||
stream << "('" << iocGroupToString(IOCGROUP(arg)) << "'), ";
|
||||
stream << std::dec << (arg & 0xFF) << ", " << IOCPARM_LEN(arg) << " }";
|
||||
}
|
||||
|
||||
static std::string ioctlToString(unsigned long arg) {
|
||||
std::ostringstream stream;
|
||||
ioctlToStream(stream, arg);
|
||||
return std::move(stream).str();
|
||||
}
|
||||
|
||||
orbis::SysResult ioctl(orbis::Thread *thread, orbis::sint fd, orbis::ulong com,
|
||||
orbis::caddr_t argp) {
|
||||
std::printf("ioctl: %d %s\n", (int)fd, ioctlToString(com).c_str());
|
||||
|
||||
Ref<IoDeviceInstance> handle =
|
||||
static_cast<IoDeviceInstance *>(thread->tproc->fileDescriptors.get(fd));
|
||||
if (handle == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
if (handle->ioctl == nullptr) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
|
||||
auto result = handle->ioctl(handle.get(), com, argp);
|
||||
|
||||
if (result < 0) {
|
||||
// TODO
|
||||
thread->where();
|
||||
return ErrorCode::IO;
|
||||
}
|
||||
|
||||
thread->retval[0] = result;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult write(orbis::Thread *thread, orbis::sint fd,
|
||||
orbis::ptr<const void> data, orbis::ulong size) {
|
||||
Ref<IoDeviceInstance> handle =
|
||||
static_cast<IoDeviceInstance *>(thread->tproc->fileDescriptors.get(fd));
|
||||
if (handle == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto result = handle->write(handle.get(), data, size);
|
||||
|
||||
if (result < 0) {
|
||||
// TODO
|
||||
return ErrorCode::IO;
|
||||
}
|
||||
|
||||
thread->retval[0] = result;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult read(orbis::Thread *thread, orbis::sint fd,
|
||||
orbis::ptr<void> data, orbis::ulong size) {
|
||||
Ref<IoDeviceInstance> handle =
|
||||
static_cast<IoDeviceInstance *>(thread->tproc->fileDescriptors.get(fd));
|
||||
if (handle == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto result = handle->read(handle.get(), data, size);
|
||||
|
||||
if (result < 0) {
|
||||
// TODO
|
||||
return ErrorCode::IO;
|
||||
}
|
||||
|
||||
thread->retval[0] = result;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult pread(orbis::Thread *thread, orbis::sint fd,
|
||||
orbis::ptr<void> data, orbis::ulong size,
|
||||
orbis::ulong offset) {
|
||||
Ref<IoDeviceInstance> handle =
|
||||
static_cast<IoDeviceInstance *>(thread->tproc->fileDescriptors.get(fd));
|
||||
if (handle == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto prevPos = handle->lseek(handle.get(), 0, SEEK_CUR);
|
||||
handle->lseek(handle.get(), offset, SEEK_SET);
|
||||
auto result = handle->read(handle.get(), data, size);
|
||||
handle->lseek(handle.get(), prevPos, SEEK_SET);
|
||||
|
||||
if (result < 0) {
|
||||
// TODO
|
||||
return ErrorCode::IO;
|
||||
}
|
||||
|
||||
thread->retval[0] = result;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult pwrite(orbis::Thread *thread, orbis::sint fd,
|
||||
orbis::ptr<const void> data, orbis::ulong size,
|
||||
orbis::ulong offset) {
|
||||
return ErrorCode::NOTSUP;
|
||||
}
|
||||
orbis::SysResult lseek(orbis::Thread *thread, orbis::sint fd,
|
||||
orbis::ulong offset, orbis::sint whence) {
|
||||
Ref<IoDeviceInstance> handle =
|
||||
static_cast<IoDeviceInstance *>(thread->tproc->fileDescriptors.get(fd));
|
||||
if (handle == nullptr) {
|
||||
return ErrorCode::BADF;
|
||||
}
|
||||
|
||||
auto result = handle->lseek(handle.get(), offset, whence);
|
||||
|
||||
if (result < 0) {
|
||||
// TODO
|
||||
return ErrorCode::IO;
|
||||
}
|
||||
|
||||
thread->retval[0] = result;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult ftruncate(orbis::Thread *thread, orbis::sint fd,
|
||||
orbis::off_t length) {
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult truncate(orbis::Thread *thread, orbis::ptr<const char> path,
|
||||
orbis::off_t length) {
|
||||
return ErrorCode::NOTSUP;
|
||||
orbis::sint protocol, Ref<File> *file) {
|
||||
return createSocket(file, name, domain, type, protocol);
|
||||
}
|
||||
|
||||
orbis::SysResult dynlib_get_obj_member(orbis::Thread *thread,
|
||||
|
|
@ -793,15 +532,6 @@ ProcessOps rx::procOpsTable = {
|
|||
.virtual_query = virtual_query,
|
||||
.open = open,
|
||||
.socket = socket,
|
||||
.close = close,
|
||||
.ioctl = ioctl,
|
||||
.write = write,
|
||||
.read = read,
|
||||
.pread = pread,
|
||||
.pwrite = pwrite,
|
||||
.lseek = lseek,
|
||||
.ftruncate = ftruncate,
|
||||
.truncate = truncate,
|
||||
.dynlib_get_obj_member = dynlib_get_obj_member,
|
||||
.dynlib_dlsym = dynlib_dlsym,
|
||||
.dynlib_do_copy_relocations = dynlib_do_copy_relocations,
|
||||
|
|
|
|||
152
rpcsx-os/scheduler.hpp
Normal file
152
rpcsx-os/scheduler.hpp
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <forward_list>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <orbis/thread/Thread.hpp>
|
||||
#include <sys/ucontext.h>
|
||||
#include <thread>
|
||||
#include <ucontext.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace rx {
|
||||
class Scheduler {
|
||||
struct CpuState {
|
||||
std::mutex mtx;
|
||||
std::condition_variable cond;
|
||||
orbis::Thread *task = nullptr;
|
||||
ucontext_t cpuContext;
|
||||
};
|
||||
|
||||
struct Task {
|
||||
orbis::Thread *thread;
|
||||
std::function<bool()> wakeupCondFn;
|
||||
};
|
||||
|
||||
std::mutex taskMtx;
|
||||
std::condition_variable taskCond;
|
||||
std::mutex queueMtx;
|
||||
std::multimap<int, Task, std::greater<>> mQueue;
|
||||
std::forward_list<CpuState> mCpuStates;
|
||||
std::vector<std::thread> mCpus;
|
||||
std::thread mThread;
|
||||
std::atomic<bool> mExit{false};
|
||||
|
||||
public:
|
||||
Scheduler(std::size_t smpCount) {
|
||||
mCpus.resize(smpCount);
|
||||
|
||||
for (std::size_t i = 0; i < smpCount; ++i) {
|
||||
auto state = &mCpuStates.emplace_front();
|
||||
mCpus[i] = std::thread{[=, this] { cpuEntry(i, state); }};
|
||||
}
|
||||
|
||||
mThread = std::thread{[this] { schedulerEntry(); }};
|
||||
}
|
||||
|
||||
~Scheduler() {
|
||||
mExit = true;
|
||||
taskCond.notify_one();
|
||||
|
||||
for (auto &cpuState : mCpuStates) {
|
||||
cpuState.cond.notify_one();
|
||||
}
|
||||
|
||||
mThread.join();
|
||||
|
||||
for (auto &cpu : mCpus) {
|
||||
cpu.join();
|
||||
}
|
||||
}
|
||||
|
||||
void enqueue(orbis::Thread *thread) {
|
||||
std::lock_guard lockQueue(queueMtx);
|
||||
mQueue.emplace(thread->prio, Task{.thread = thread});
|
||||
taskCond.notify_one();
|
||||
}
|
||||
|
||||
[[noreturn]] void
|
||||
releaseThisCpu(orbis::Thread *thread,
|
||||
std::function<bool()> wakeupCondFn = nullptr) {
|
||||
auto cpuContext = static_cast<CpuState *>(thread->cpuContext);
|
||||
thread->cpuContext = nullptr;
|
||||
thread->cpuIndex = -1;
|
||||
mQueue.emplace(thread->prio, Task{.thread = thread,
|
||||
.wakeupCondFn = std::move(wakeupCondFn)});
|
||||
cpuContext->task = nullptr;
|
||||
::setcontext(&cpuContext->cpuContext);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
private:
|
||||
[[noreturn]] void invoke(orbis::Thread *thread) {
|
||||
auto ctxt = reinterpret_cast<ucontext_t *>(thread->context);
|
||||
::setcontext(ctxt);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
orbis::Thread *fetchTask() {
|
||||
std::lock_guard lockQueue(queueMtx);
|
||||
decltype(mQueue)::iterator foundIt = mQueue.end();
|
||||
for (auto it = mQueue.begin(); it != mQueue.end(); ++it) {
|
||||
auto &[prio, task] = *it;
|
||||
if (task.wakeupCondFn != nullptr && !task.wakeupCondFn()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (foundIt == mQueue.end() || foundIt->first < task.thread->prio) {
|
||||
foundIt = it;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundIt != mQueue.end()) {
|
||||
auto result = foundIt->second.thread;
|
||||
mQueue.erase(foundIt);
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void schedulerEntry() {
|
||||
while (!mExit.load(std::memory_order::relaxed)) {
|
||||
if (mQueue.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_lock lock(taskMtx);
|
||||
taskCond.wait(lock);
|
||||
|
||||
for (auto &cpu : mCpuStates) {
|
||||
if (cpu.task == nullptr) {
|
||||
cpu.task = fetchTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cpuEntry(std::size_t cpuIndex, CpuState *state) {
|
||||
::getcontext(&state->cpuContext);
|
||||
|
||||
while (!mExit.load(std::memory_order::relaxed)) {
|
||||
auto task = std::exchange(state->task, nullptr);
|
||||
if (task == nullptr) {
|
||||
taskCond.notify_one();
|
||||
|
||||
std::unique_lock lock(state->mtx);
|
||||
state->cond.wait(lock);
|
||||
task = std::exchange(state->task, nullptr);
|
||||
}
|
||||
|
||||
if (task != nullptr) {
|
||||
task->cpuIndex = cpuIndex;
|
||||
task->cpuContext = state;
|
||||
invoke(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace rx
|
||||
|
|
@ -26,7 +26,7 @@ orbis::SysResult rx::vfs::mount(const std::filesystem::path &guestPath,
|
|||
}
|
||||
|
||||
orbis::SysResult rx::vfs::open(std::string_view path, int flags, int mode,
|
||||
orbis::Ref<IoDeviceInstance> *instance) {
|
||||
orbis::Ref<orbis::File> *file) {
|
||||
orbis::Ref<IoDevice> device;
|
||||
bool isCharacterDevice = path.starts_with("/dev/");
|
||||
|
||||
|
|
@ -50,8 +50,8 @@ orbis::SysResult rx::vfs::open(std::string_view path, int flags, int mode,
|
|||
}
|
||||
|
||||
if (device != nullptr) {
|
||||
return (orbis::ErrorCode)device->open(
|
||||
device.get(), instance, std::string(path).c_str(), flags, mode);
|
||||
return (orbis::ErrorCode)device->open(file, std::string(path).c_str(),
|
||||
flags, mode);
|
||||
}
|
||||
|
||||
if (isCharacterDevice) {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "orbis/error/SysResult.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Rc.hpp"
|
||||
#include <filesystem>
|
||||
|
||||
struct IoDevice;
|
||||
struct IoDeviceInstance;
|
||||
|
||||
namespace rx::vfs {
|
||||
void initialize();
|
||||
void deinitialize();
|
||||
orbis::SysResult mount(const std::filesystem::path &guestPath, IoDevice *dev);
|
||||
orbis::SysResult open(std::string_view path, int flags, int mode,
|
||||
orbis::Ref<IoDeviceInstance> *instance);
|
||||
orbis::Ref<orbis::File> *file);
|
||||
} // namespace rx::vfs
|
||||
|
|
|
|||
Loading…
Reference in a new issue