diff --git a/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp b/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp index 434436a92..8f3656348 100644 --- a/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp +++ b/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp @@ -1,10 +1,10 @@ #pragma once +#include #include #include #include #include -#include namespace amdgpu::bridge { extern std::uint32_t expGpuPid; @@ -45,7 +45,8 @@ enum class CommandId : std::uint32_t { Nop, ProtectMemory, CommandBuffer, - Flip + Flip, + MapDmem, }; struct CmdMemoryProt { @@ -77,6 +78,15 @@ struct CmdFlip { std::uint64_t arg; }; +struct CmdMapDmem { + std::uint64_t offset; + std::uint64_t address; + std::uint64_t size; + std::uint32_t prot; + std::uint32_t pid; + std::uint32_t dmemIndex; +}; + enum { kPageWriteWatch = 1 << 0, kPageReadWriteLock = 1 << 1, @@ -91,6 +101,7 @@ struct BridgeHeader { std::uint64_t info; std::uint32_t pullerPid; std::uint32_t pusherPid; + std::atomic lock; volatile std::uint64_t flags; std::uint64_t vmAddress; std::uint64_t vmSize; @@ -103,7 +114,7 @@ struct BridgeHeader { std::uint32_t memoryAreaCount; std::uint32_t commandBufferCount; std::uint32_t bufferCount; - CmdMemoryProt memoryAreas[128]; + CmdMemoryProt memoryAreas[512]; CmdCommandBuffer commandBuffers[32]; CmdBuffer buffers[10]; // orbis::shared_mutex cacheCommandMtx; @@ -125,6 +136,7 @@ struct Command { CmdCommandBuffer commandBuffer; CmdBuffer buffer; CmdFlip flip; + CmdMapDmem mapDmem; }; }; @@ -137,9 +149,6 @@ enum class BridgeFlags { struct BridgePusher { BridgeHeader *header = nullptr; - BridgePusher() = default; - BridgePusher(BridgeHeader *header) : header(header) {} - void setVm(std::uint64_t address, std::uint64_t size, const char *name) { header->vmAddress = address; header->vmSize = size; @@ -155,6 +164,12 @@ struct BridgePusher { } } + void sendMapDmem(std::uint32_t pid, std::uint32_t dmemIndex, std::uint64_t address, std::uint64_t size, std::uint32_t prot, std::uint64_t offset) { + if (pid == expGpuPid) { + sendCommand(CommandId::MapDmem, {pid, dmemIndex, address, size, prot, offset}); + } + } + void sendCommandBuffer(std::uint32_t pid, std::uint64_t queue, std::uint64_t address, std::uint64_t size) { if (pid == expGpuPid) { @@ -181,6 +196,11 @@ private: } void sendCommand(CommandId id, std::initializer_list args) { + std::uint64_t exp = 0; + while (!header->lock.compare_exchange_weak(exp, 1, std::memory_order::acquire, std::memory_order::relaxed)) { + exp = 0; + } + std::size_t cmdSize = args.size() + 1; std::uint64_t pos = getPushPosition(cmdSize); @@ -189,6 +209,7 @@ private: header->commands[pos++] = arg; } header->push = pos; + header->lock.store(0, std::memory_order::release); } std::uint64_t getPushPosition(std::uint64_t cmdSize) { @@ -279,6 +300,15 @@ private: result.flip.bufferIndex = args[1]; result.flip.arg = args[2]; return result; + + case CommandId::MapDmem: + result.mapDmem.pid = args[0]; + result.mapDmem.dmemIndex = args[1]; + result.mapDmem.address = args[2]; + result.mapDmem.size = args[3]; + result.mapDmem.prot = args[4]; + result.mapDmem.offset = args[5]; + return result; } __builtin_trap(); diff --git a/hw/amdgpu/device/src/device.cpp b/hw/amdgpu/device/src/device.cpp index d48555ee7..bb7e3b435 100644 --- a/hw/amdgpu/device/src/device.cpp +++ b/hw/amdgpu/device/src/device.cpp @@ -43,7 +43,7 @@ using namespace amdgpu::device; static const bool kUseDirectMemory = false; static amdgpu::bridge::BridgeHeader *g_bridge; -void *g_rwMemory; +// void *g_rwMemory; std::size_t g_memorySize; std::uint64_t g_memoryBase; RemoteMemory g_hostMemory; @@ -4577,6 +4577,9 @@ static auto g_commandHandlers = [] { static void handleCommandBuffer(TaskChain &waitTaskSet, QueueRegisters ®s, std::span &packets) { while (!packets.empty()) { + // std::uint64_t address = + // (char *)packets.data() - g_hostMemory.shmPointer + 0x40000; + // std::fprintf(stderr, "address = %lx\n", address); auto cmd = packets[0]; auto type = getBits(cmd, 31, 30); @@ -4637,29 +4640,29 @@ void amdgpu::device::AmdgpuDevice::handleProtectMemory(std::uint64_t address, break; case PROT_WRITE | PROT_READ: - protStr = "W"; + protStr = "RW"; break; default: protStr = "unknown"; break; } - std::printf("Allocated area at %zx, size %lx, prot %s\n", address, size, - protStr); + std::fprintf(stderr, "Allocated area at %zx, size %lx, prot %s\n", address, + size, protStr); } else { memoryAreaTable.unmap(beginPage, endPage); - std::printf("Unmapped area at %zx, size %lx\n", address, size); + std::fprintf(stderr, "Unmapped area at %zx, size %lx\n", address, size); } std::size_t index = 0; for (auto area : memoryAreaTable) { + // std::printf("area %lx-%lx\n", area.beginAddress * kPageSize, + // area.endAddress * kPageSize); + if (index >= std::size(g_bridge->memoryAreas)) { util::unreachable("too many memory areas"); } - // std::printf("area %lx-%lx\n", area.beginAddress * kPageSize, - // area.endAddress * kPageSize); - g_bridge->memoryAreas[index++] = { .address = area.beginAddress * kPageSize, .size = (area.endAddress - area.beginAddress) * kPageSize, @@ -4685,11 +4688,16 @@ void amdgpu::device::AmdgpuDevice::handleCommandBuffer(std::uint64_t queueId, if (inserted) { std::printf("creation queue %lx\n", queueId); - it->second.sched.enqueue([=, queue = &it->second] { - if (queueId == 0xc0023f00) { - setThreadName("Graphics queue"); - } else { - setThreadName(("Compute queue" + std::to_string(queueId)).c_str()); + it->second.sched.enqueue([=, queue = &it->second, + initialized = false] mutable { + if (!initialized) { + initialized = true; + + if (queueId == 0xc0023f00) { + setThreadName("Graphics queue"); + } else { + setThreadName(("Compute queue" + std::to_string(queueId)).c_str()); + } } Queue::CommandBuffer *commandBuffer; @@ -4715,7 +4723,7 @@ void amdgpu::device::AmdgpuDevice::handleCommandBuffer(std::uint64_t queueId, }); } - // std::printf("address = %lx, count = %lx\n", address, count); + // std::fprintf(stderr, "address = %lx, count = %lx\n", address, count); std::lock_guard lock(it->second.mtx); it->second.commandBuffers.push_back( diff --git a/orbis-kernel/include/orbis/SocketAddress.hpp b/orbis-kernel/include/orbis/SocketAddress.hpp new file mode 100644 index 000000000..78b6cdc31 --- /dev/null +++ b/orbis-kernel/include/orbis/SocketAddress.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace orbis { +struct SocketAddress { + unsigned char len; + unsigned char family; + char data[14]; +}; +} // namespace orbis \ No newline at end of file diff --git a/orbis-kernel/include/orbis/file.hpp b/orbis-kernel/include/orbis/file.hpp index 364dd7380..bd3ee7c56 100644 --- a/orbis-kernel/include/orbis/file.hpp +++ b/orbis-kernel/include/orbis/file.hpp @@ -14,6 +14,9 @@ struct KNote; struct Thread; struct Stat; struct Uio; +struct SocketAddress; +struct msghdr; +struct sf_hdtr; struct FileOps { std::int32_t flags; @@ -41,6 +44,33 @@ struct FileOps { Thread *thread) = nullptr; ErrorCode (*munmap)(File *file, void **address, std::uint64_t size, Thread *thread) = nullptr; + + ErrorCode (*bind)(orbis::File *file, SocketAddress *address, + std::size_t addressLen, Thread *thread) = nullptr; + ErrorCode (*listen)(orbis::File *file, int backlog, Thread *thread) = nullptr; + ErrorCode (*accept)(orbis::File *file, SocketAddress *address, + std::uint32_t *addressLen, Thread *thread) = nullptr; + ErrorCode (*connect)(orbis::File *file, SocketAddress *address, + std::uint32_t addressLen, Thread *thread) = nullptr; + ErrorCode (*sendto)(orbis::File *file, const void *buf, size_t len, + sint flags, caddr_t to, sint tolen, + Thread *thread) = nullptr; + ErrorCode (*sendmsg)(orbis::File *file, msghdr *msg, sint flags, + Thread *thread) = nullptr; + ErrorCode (*recvfrom)(orbis::File *file, void *buf, size_t len, + sint flags, SocketAddress *from, uint32_t *fromlenaddr, + Thread *thread) = nullptr; + ErrorCode (*recvmsg)(orbis::File *file, msghdr *msg, sint flags, + Thread *thread) = nullptr; + ErrorCode (*shutdown)(orbis::File *file, sint how, Thread *thread) = nullptr; + ErrorCode (*setsockopt)(orbis::File *file, sint level, sint name, + const void *val, sint valsize, + Thread *thread) = nullptr; + ErrorCode (*getsockopt)(orbis::File *file, sint level, sint name, void *val, + sint *avalsize, Thread *thread) = nullptr; + ErrorCode (*sendfile)(orbis::File *file, sint fd, off_t offset, size_t nbytes, + ptr hdtr, ptr sbytes, sint flags, + Thread *thread) = nullptr; }; struct File : RcBase { @@ -49,6 +79,7 @@ struct File : RcBase { const FileOps *ops = nullptr; Ref device; std::uint64_t nextOff = 0; + int hostFd = -1; utils::kvector dirEntries; }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/ipmi.hpp b/orbis-kernel/include/orbis/ipmi.hpp index cfd2dce15..5093ad0af 100644 --- a/orbis-kernel/include/orbis/ipmi.hpp +++ b/orbis-kernel/include/orbis/ipmi.hpp @@ -80,7 +80,6 @@ struct IpmiSession : RcBase { EventFlag evf{0, 0}; shared_cv connectCv; bool expectedOutput = false; // TODO: verify - bool connected = false; // TODO: implement more states sint connectionStatus{0}; }; @@ -152,8 +151,16 @@ SysResult sysIpmiSendConnectResult(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); SysResult sysIpmiSessionRespondSync(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); +SysResult sysIpmiClientGetMessage(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); SysResult sysIpmiClientTryGetMessage(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); +SysResult sysIpmiSessionTrySendMessage(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz); +SysResult sysIpmiClientDisconnect(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz); SysResult sysIpmiSessionGetClientPid(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); SysResult sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, diff --git a/orbis-kernel/include/orbis/note.hpp b/orbis-kernel/include/orbis/note.hpp index ea3dc1b1d..0e9692fd1 100644 --- a/orbis-kernel/include/orbis/note.hpp +++ b/orbis-kernel/include/orbis/note.hpp @@ -7,7 +7,7 @@ #include namespace orbis { - +struct File; static constexpr auto kEvFiltRead = -1; static constexpr auto kEvFiltWrite = -2; static constexpr auto kEvFiltAio = -3; @@ -75,6 +75,7 @@ struct KQueue; struct KNote { shared_mutex mutex; Ref queue; + Ref file; KEvent event{}; bool enabled = true; bool triggered = false; diff --git a/orbis-kernel/include/orbis/sys/sysproto.hpp b/orbis-kernel/include/orbis/sys/sysproto.hpp index 0c94cc1b6..fcdeb9659 100644 --- a/orbis-kernel/include/orbis/sys/sysproto.hpp +++ b/orbis-kernel/include/orbis/sys/sysproto.hpp @@ -20,6 +20,7 @@ struct timespec; struct Stat; struct stack_t; struct IoVec; +struct BatchMapEntry; SysResult nosys(Thread *thread); @@ -53,13 +54,13 @@ SysResult sys_recvmsg(Thread *thread, sint s, ptr msg, SysResult sys_sendmsg(Thread *thread, sint s, ptr msg, sint flags); SysResult sys_recvfrom(Thread *thread, sint s, caddr_t buf, size_t len, - sint flags, ptr from, + sint flags, ptr from, ptr fromlenaddr); -SysResult sys_accept(Thread *thread, sint s, ptr from, +SysResult sys_accept(Thread *thread, sint s, ptr from, ptr fromlenaddr); -SysResult sys_getpeername(Thread *thread, sint fdes, ptr asa, +SysResult sys_getpeername(Thread *thread, sint fdes, ptr asa, ptr alen); -SysResult sys_getsockname(Thread *thread, sint fdes, ptr asa, +SysResult sys_getsockname(Thread *thread, sint fdes, ptr asa, ptr alen); SysResult sys_access(Thread *thread, ptr path, sint flags); SysResult sys_chflags(Thread *thread, ptr path, sint flags); @@ -634,7 +635,8 @@ SysResult sys_evf_cancel(Thread *thread, sint id, uint64_t value, ptr pNumWaitThreads); SysResult sys_query_memory_protection(Thread *thread, ptr address, ptr protection); -SysResult sys_batch_map(Thread *thread /* TODO */); +SysResult sys_batch_map(Thread *thread, sint unk, sint flags, ptr entries, + sint entriesCount, ptr processedCount); SysResult sys_osem_create(Thread *thread, ptr name, uint attrs, sint initCount, sint maxCount); SysResult sys_osem_delete(Thread *thread, sint id); @@ -720,7 +722,8 @@ SysResult sys_get_proc_type_info(Thread *thread, ptr destProcessInfo); SysResult sys_get_resident_count(Thread *thread, pid_t pid); SysResult sys_prepare_to_suspend_process(Thread *thread, pid_t pid); SysResult sys_get_resident_fmem_count(Thread *thread, pid_t pid); -SysResult sys_thr_get_name(Thread *thread, lwpid_t lwpid); +SysResult sys_thr_get_name(Thread *thread, lwpid_t lwpid, char *buf, + size_t buflen); SysResult sys_set_gpo(Thread *thread /* TODO */); SysResult sys_get_paging_stats_of_all_objects(Thread *thread /* TODO */); SysResult sys_test_debug_rwmem(Thread *thread /* TODO */); diff --git a/orbis-kernel/include/orbis/thread/ProcessOps.hpp b/orbis-kernel/include/orbis/thread/ProcessOps.hpp index dba815821..b07293e6a 100644 --- a/orbis-kernel/include/orbis/thread/ProcessOps.hpp +++ b/orbis-kernel/include/orbis/thread/ProcessOps.hpp @@ -51,6 +51,8 @@ struct ProcessOps { SysResult (*blockpool_unmap)(Thread *thread, caddr_t addr, size_t len); SysResult (*socket)(Thread *thread, ptr name, sint domain, sint type, sint protocol, Ref *file); + SysResult (*socketpair)(Thread *thread, sint domain, sint type, sint protocol, + Ref *a, Ref *b); SysResult (*shm_unlink)(Thread *thread, const char *path); SysResult (*dynlib_get_obj_member)(Thread *thread, ModuleHandle handle, uint64_t index, ptr> addrp); diff --git a/orbis-kernel/include/orbis/uio.hpp b/orbis-kernel/include/orbis/uio.hpp index f1f8c4768..d822af465 100644 --- a/orbis-kernel/include/orbis/uio.hpp +++ b/orbis-kernel/include/orbis/uio.hpp @@ -1,6 +1,9 @@ #pragma once +#include #include +#include +#include namespace orbis { struct IoVec { @@ -25,5 +28,27 @@ struct Uio { UioSeg segflg; UioRw rw; void *td; + + std::size_t write(const void *data, std::size_t size) { + auto pos = reinterpret_cast(data); + auto end = pos + size; + + for (auto vec : std::span(iov, iovcnt)) { + if (pos >= end) { + break; + } + + auto nextPos = std::min(pos + vec.len, end); + std::memcpy(vec.base, pos, nextPos - pos); + pos = nextPos; + } + + return size - (end - pos); + } + + template + std::size_t write(const T &object) { + return write(&object, sizeof(T)); + } }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/utils/Rc.hpp b/orbis-kernel/include/orbis/utils/Rc.hpp index 8992a375f..20ecb5d21 100644 --- a/orbis-kernel/include/orbis/utils/Rc.hpp +++ b/orbis-kernel/include/orbis/utils/Rc.hpp @@ -20,7 +20,7 @@ struct RcBase { void incRef() { if (!_total_size) std::abort(); - if (references.fetch_add(1, std::memory_order::relaxed) > 512) { + if (references.fetch_add(1, std::memory_order::relaxed) > 4096) { assert(!"too many references"); } } @@ -81,7 +81,7 @@ public: template requires(std::is_base_of_v) Ref &operator=(Ref &&other) { - other.swap(*this); + other.template cast().swap(*this); return *this; } diff --git a/orbis-kernel/src/ipmi.cpp b/orbis-kernel/src/ipmi.cpp index bb86a189a..b039c3af5 100644 --- a/orbis-kernel/src/ipmi.cpp +++ b/orbis-kernel/src/ipmi.cpp @@ -340,6 +340,23 @@ orbis::SysResult orbis::sysIpmiSessionRespondSync(Thread *thread, session->responseCv.notify_one(session->mutex); return uwrite(result, 0u); } +orbis::SysResult orbis::sysIpmiClientGetMessage(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + auto client = thread->tproc->ipmiMap.get(kid).cast(); + + if (client == nullptr) { + return ErrorCode::INVAL; + } + + ORBIS_LOG_ERROR(__FUNCTION__, client->name, client->messages.size(), + paramsSz); + while (true) { + std::this_thread::sleep_for(std::chrono::days(1)); + } + return uwrite(result, 0x80020000 + static_cast(ErrorCode::AGAIN)); +} orbis::SysResult orbis::sysIpmiClientTryGetMessage(Thread *thread, ptr result, uint kid, @@ -365,6 +382,8 @@ orbis::SysResult orbis::sysIpmiClientTryGetMessage(Thread *thread, return ErrorCode::INVAL; } + // ORBIS_LOG_ERROR(__FUNCTION__, client->name, client->messages.size()); + SceIpmiClientTryGetArgs _params; ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); @@ -389,6 +408,81 @@ orbis::SysResult orbis::sysIpmiClientTryGetMessage(Thread *thread, return uwrite(result, 0); } +orbis::SysResult orbis::sysIpmiSessionTrySendMessage(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + struct SceIpmiClientTrySendArgs { + uint32_t unk; // 0 + uint32_t padding; + ptr message; + uint64_t size; + }; + + static_assert(sizeof(SceIpmiClientTrySendArgs) == 0x18); + + if (paramsSz != sizeof(SceIpmiClientTrySendArgs)) { + return ErrorCode::INVAL; + } + + auto session = thread->tproc->ipmiMap.get(kid).cast(); + + if (session == nullptr) { + return ErrorCode::INVAL; + } + + SceIpmiClientTrySendArgs _params; + ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); + + std::lock_guard lock(session->mutex); + + if (session->client == nullptr) { + return ErrorCode::INVAL; + } + + auto client = session->client; + std::lock_guard lockClient(client->mutex); + + ORBIS_LOG_ERROR(__FUNCTION__, session->server->name, client->name, + client->messages.size(), _params.message, _params.size); + auto &message = client->messages.emplace_back(); + message.resize(_params.size); + ORBIS_RET_ON_ERROR(ureadRaw(message.data(), _params.message, _params.size)); + client->messageCv.notify_one(client->mutex); + return uwrite(result, 0); +} + +orbis::SysResult orbis::sysIpmiClientDisconnect(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + struct SceIpmiClientDisconnectArgs { + ptr status; + }; + + if (paramsSz != sizeof(SceIpmiClientDisconnectArgs)) { + return ErrorCode::INVAL; + } + + auto client = thread->tproc->ipmiMap.get(kid).cast(); + + if (client == nullptr) { + return ErrorCode::INVAL; + } + + SceIpmiClientDisconnectArgs _params; + ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); + + ORBIS_LOG_ERROR(__FUNCTION__, client->name, _params.status); + + std::lock_guard lock(client->mutex); + + auto &message = client->messages.front(); + + ORBIS_RET_ON_ERROR(uwrite(_params.status, 0)); + return uwrite(result, 0); +} + orbis::SysResult orbis::sysIpmiSessionGetClientPid(Thread *thread, ptr result, uint kid, ptr params, @@ -474,7 +568,6 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint kid, // _params.numInData, _params.unk, _params.numOutData, // _params.pInData, _params.pOutData, _params.pResult, // _params.flags); - std::size_t inSize = 0; for (auto &data : std::span(_params.pInData, _params.numInData)) { inSize += data.size; @@ -499,8 +592,6 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint kid, ORBIS_LOG_TODO("IPMI: sync call", client->name, _params.method, thread->tproc->pid); - thread->where(); - auto bufLoc = std::bit_cast(msg + 1); for (auto &data : std::span(_params.pInData, _params.numInData)) { @@ -539,6 +630,10 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint kid, auto response = std::move(session->messageResponses.front()); session->messageResponses.pop_front(); + if (response.errorCode != 0) { + thread->where(); + } + ORBIS_RET_ON_ERROR(uwrite(_params.pResult, response.errorCode)); if (_params.numOutData > 0 && _params.pOutData->size < response.data.size()) { return ErrorCode::INVAL; @@ -753,11 +848,12 @@ orbis::SysResult orbis::sysIpmiClientPollEventFlag(Thread *thread, return ErrorCode::INVAL; } - ORBIS_LOG_TODO(__FUNCTION__, client->name, _params.index, _params.patternSet, - _params.mode, _params.pPatternSet); + // ORBIS_LOG_TODO(__FUNCTION__, client->name, _params.index, + // _params.patternSet, + // _params.mode, _params.pPatternSet); ORBIS_RET_ON_ERROR(uwrite(_params.pPatternSet, 0u)); // client->evf.set(_params.a); - return ErrorCode::BUSY; + return SysResult::notAnError(ErrorCode::BUSY); } orbis::SysResult orbis::sysIpmiSessionWaitEventFlag(Thread *thread, diff --git a/orbis-kernel/src/pipe.cpp b/orbis-kernel/src/pipe.cpp index 83b7367b1..fc2c7f155 100644 --- a/orbis-kernel/src/pipe.cpp +++ b/orbis-kernel/src/pipe.cpp @@ -1,7 +1,9 @@ #include "pipe.hpp" #include "error/ErrorCode.hpp" #include "file.hpp" +#include "thread/Thread.hpp" #include "uio.hpp" +#include "utils/Logs.hpp" #include static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio, @@ -9,16 +11,31 @@ static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio, auto pipe = static_cast(file); while (true) { if (pipe->data.empty()) { - pipe->cv.wait(file->mtx); - continue; + // pipe->cv.wait(file->mtx); + // ORBIS_LOG_ERROR(__FUNCTION__, "wakeup", thread->name, thread->tid, file); + // continue; + return orbis::ErrorCode::WOULDBLOCK; } for (auto vec : std::span(uio->iov, uio->iovcnt)) { auto size = std::min(pipe->data.size(), vec.len); + + if (size == 0) { + pipe->data.clear(); + continue; + } + + if (size > pipe->data.size()) { + size = pipe->data.size(); + } + uio->offset += size; std::memcpy(vec.base, pipe->data.data(), size); + ORBIS_LOG_ERROR(__FUNCTION__, thread->name, thread->tid, file, size, pipe->data.size(), uio->offset, file->nextOff); + if (pipe->data.size() == size) { + pipe->data.clear(); break; } @@ -37,20 +54,30 @@ static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio, static orbis::ErrorCode pipe_write(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) { auto pipe = static_cast(file); + ORBIS_LOG_ERROR(__FUNCTION__, thread->name, thread->tid, file); + std::size_t cnt = 0; for (auto vec : std::span(uio->iov, uio->iovcnt)) { auto offset = pipe->data.size(); pipe->data.resize(offset + vec.len); - std::memcpy(pipe->data.data(), vec.base, vec.len); + ORBIS_RET_ON_ERROR(orbis::ureadRaw(pipe->data.data(), vec.base, vec.len)); + cnt += vec.len; } file->event.emit(orbis::kEvFiltRead); pipe->cv.notify_one(file->mtx); - uio->resid = 0; - return {}; + uio->resid -= cnt; + uio->offset += cnt; + + ORBIS_LOG_ERROR(__FUNCTION__, thread->name, thread->tid, file, uio->resid, uio->offset, file->nextOff, cnt); + thread->where(); + return{}; } -static orbis::FileOps pipe_ops = {.read = pipe_read, .write = pipe_write}; +static orbis::FileOps pipe_ops = { + .read = pipe_read, + .write = pipe_write, +}; orbis::Ref orbis::createPipe() { auto result = knew(); diff --git a/orbis-kernel/src/sys/sys_event.cpp b/orbis-kernel/src/sys/sys_event.cpp index e88e7ba6b..7c687cae7 100644 --- a/orbis-kernel/src/sys/sys_event.cpp +++ b/orbis-kernel/src/sys/sys_event.cpp @@ -7,6 +7,7 @@ #include #include #include +#include orbis::SysResult orbis::sys_kqueue(Thread *thread) { auto queue = knew(); @@ -33,6 +34,28 @@ orbis::SysResult orbis::sys_kqueueex(Thread *thread, ptr name, return {}; } +static bool isReadEventTriggered(int hostFd) { + fd_set fds{}; + FD_SET(hostFd, &fds); + timeval timeout{}; + if (::select(hostFd + 1, &fds, nullptr, nullptr, &timeout) < 0) { + return false; + } + + return FD_ISSET(hostFd, &fds); +} + +static bool isWriteEventTriggered(int hostFd) { + fd_set fds{}; + FD_SET(hostFd, &fds); + timeval timeout{}; + if (::select(hostFd + 1, nullptr, &fds, nullptr, &timeout) < 0) { + return false; + } + + return FD_ISSET(hostFd, &fds); +} + namespace orbis { static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) { auto nodeIt = kq->notes.end(); @@ -82,11 +105,11 @@ static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) { } std::unique_lock lock(fd->event.mutex); - - if (change.filter == kEvFiltWrite) { - nodeIt->triggered = true; - kq->cv.notify_all(kq->mtx); - } + nodeIt->file = fd; + // if (change.filter == kEvFiltWrite) { + // nodeIt->triggered = true; + // kq->cv.notify_all(kq->mtx); + // } fd->event.notes.insert(&*nodeIt); } @@ -176,14 +199,16 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, for (auto &changePtr : std::span(changelist, nchanges)) { KEvent change; ORBIS_RET_ON_ERROR(uread(change, &changePtr)); - ORBIS_LOG_TODO(__FUNCTION__, change.ident, change.filter, change.flags, - change.fflags, change.data, change.udata); + ORBIS_LOG_TODO(__FUNCTION__, fd, change.ident, change.filter, + change.flags, change.fflags, change.data, change.udata); if (auto result = keventChange(kq.get(), change, thread); result.value() != 0) { return result; } } + + kq->cv.notify_all(kq->mtx); } } @@ -217,7 +242,17 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, std::vector result; result.reserve(nevents); + if (kq->notes.empty()) { + // ORBIS_LOG_ERROR(__FUNCTION__, "attempt to wait empty kqueue", fd, + // nevents, timeoutPoint.time_since_epoch().count()); thread->where(); + // return{}; + // std::abort(); + return {}; + } + while (true) { + bool waitHack = false; + bool canSleep = true; std::lock_guard lock(kq->mtx); for (auto it = kq->notes.begin(); it != kq->notes.end();) { if (result.size() >= nevents) { @@ -227,9 +262,32 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, auto ¬e = *it; std::lock_guard lock(note.mutex); + if (!note.triggered) { + if (note.event.filter == kEvFiltRead) { + if (note.file->hostFd < 0 || + isReadEventTriggered(note.file->hostFd)) { + note.triggered = true; + } else { + canSleep = false; + } + } else if (note.event.filter == kEvFiltWrite) { + if (note.file->hostFd < 0 || + isWriteEventTriggered(note.file->hostFd)) { + note.triggered = true; + } else { + canSleep = false; + } + } + } + if (note.enabled && note.triggered) { result.push_back(note.event); + if (note.event.filter == kEvFiltGraphicsCore || + note.event.filter == kEvFiltDisplay) { + waitHack = true; + } + if (note.event.flags & kEvDispatch) { note.enabled = false; } @@ -244,6 +302,9 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, } if (!result.empty()) { + // if (waitHack) { + // std::this_thread::sleep_for(std::chrono::milliseconds(3)); + // } break; } @@ -256,9 +317,13 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, auto waitTimeout = std::chrono::duration_cast( timeoutPoint - now); - kq->cv.wait(kq->mtx, waitTimeout.count()); + if (canSleep) { + kq->cv.wait(kq->mtx, waitTimeout.count()); + } } else { - kq->cv.wait(kq->mtx); + if (canSleep) { + kq->cv.wait(kq->mtx); + } } } diff --git a/orbis-kernel/src/sys/sys_sce.cpp b/orbis-kernel/src/sys/sys_sce.cpp index ddea76e06..bbb66f3b4 100644 --- a/orbis-kernel/src/sys/sys_sce.cpp +++ b/orbis-kernel/src/sys/sys_sce.cpp @@ -137,6 +137,11 @@ orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op, return {}; } + if (int_value->encoded_id == 0x29b56169422aa3dd) { + int_value->value = 2; + return {}; + } + // 0x503f69bde385a6ac // allow loading from dev machine? // 0x2d946f62aef8f878 @@ -162,7 +167,6 @@ orbis::SysResult orbis::sys_dl_notify_event(Thread *thread /* TODO */) { } orbis::SysResult orbis::sys_evf_create(Thread *thread, ptr name, sint attrs, uint64_t initPattern) { - ORBIS_LOG_WARNING(__FUNCTION__, name, attrs, initPattern); if (name == nullptr) { return ErrorCode::INVAL; } @@ -215,7 +219,9 @@ orbis::SysResult orbis::sys_evf_create(Thread *thread, ptr name, std::strncpy(eventFlag->name, _name, 32); } - thread->retval[0] = thread->tproc->evfMap.insert(eventFlag); + auto fd = thread->tproc->evfMap.insert(eventFlag); + thread->retval[0] = fd; + ORBIS_LOG_WARNING(__FUNCTION__, name, attrs, initPattern, fd); return {}; } orbis::SysResult orbis::sys_evf_delete(Thread *thread, sint id) { @@ -229,7 +235,6 @@ orbis::SysResult orbis::sys_evf_delete(Thread *thread, sint id) { return {}; } orbis::SysResult orbis::sys_evf_open(Thread *thread, ptr name) { - ORBIS_LOG_WARNING(__FUNCTION__, name); char _name[32]; if (auto result = ureadString(_name, sizeof(_name), (const char *)name); result != ErrorCode{}) { @@ -239,10 +244,13 @@ orbis::SysResult orbis::sys_evf_open(Thread *thread, ptr name) { auto eventFlag = thread->tproc->context->findEventFlag(_name); if (eventFlag == nullptr) { + ORBIS_LOG_ERROR(__FUNCTION__, _name, "not exists"); return ErrorCode::NOENT; } - thread->retval[0] = thread->tproc->evfMap.insert(eventFlag); + auto fd = thread->tproc->evfMap.insert(eventFlag); + thread->retval[0] = fd; + ORBIS_LOG_WARNING(__FUNCTION__, name, fd); return {}; } orbis::SysResult orbis::sys_evf_close(Thread *thread, sint id) { @@ -370,8 +378,70 @@ orbis::sys_query_memory_protection(Thread *thread, ptr address, return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_batch_map(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; + +namespace orbis { +struct BatchMapEntry { + ptr start; + off_t offset; + size_t length; + char protection; + char type; + short reserved; + sint operation; // 0 - map direct + // 1 - unmap + // 2 - protect + // 3 - map flexible + // 4 - type protect +}; +} // namespace orbis + +orbis::SysResult orbis::sys_batch_map(Thread *thread, sint unk, sint flags, + ptr entries, + sint entriesCount, + ptr processedCount) { + auto ops = thread->tproc->ops; + SysResult result = ErrorCode{}; + ORBIS_LOG_ERROR(__FUNCTION__, unk, flags, entries, entriesCount, + processedCount); + + int processed = 0; + for (int i = 0; i < entriesCount; ++i) { + BatchMapEntry _entry; + ORBIS_RET_ON_ERROR(uread(_entry, entries + i)); + ORBIS_LOG_ERROR(__FUNCTION__, _entry.operation, ptr(_entry.start), + _entry.length, int(_entry.type), int(_entry.protection), + _entry.offset); + + switch (_entry.operation) { + case 0: + result = ops->dmem_mmap(thread, _entry.start, _entry.length, _entry.type, + _entry.protection, flags, _entry.offset); + break; + case 1: + result = ops->munmap(thread, _entry.start, _entry.length); + break; + case 2: + result = + ops->mprotect(thread, _entry.start, _entry.length, _entry.protection); + break; + default: + result = ErrorCode::INVAL; + break; + } + + ORBIS_LOG_ERROR(__FUNCTION__, result.value()); + + if (result.value()) { + ORBIS_LOG_ERROR(__FUNCTION__, result.value()); + break; + } + + ++processed; + } + + thread->retval[0] = 0; + ORBIS_RET_ON_ERROR(uwrite(processedCount, processed)); + return result; } orbis::SysResult orbis::sys_osem_create(Thread *thread, ptr name, uint attrs, @@ -418,6 +488,7 @@ orbis::SysResult orbis::sys_osem_create(Thread *thread, sem = insertedSem; } else { sem = knew(attrs, initCount, maxCount); + std::strncpy(sem->name, _name, 32); } thread->retval[0] = thread->tproc->semMap.insert(sem); @@ -1048,8 +1119,26 @@ orbis::SysResult orbis::sys_prepare_to_suspend_process(Thread *thread, orbis::SysResult orbis::sys_get_resident_fmem_count(Thread *thread, pid_t pid) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_thr_get_name(Thread *thread, lwpid_t lwpid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_thr_get_name(Thread *thread, lwpid_t lwpid, + char *buf, size_t buflen) { + Thread *searchThread; + if (thread->tid == lwpid) { + searchThread = thread; + } else { + searchThread = thread->tproc->threadsMap.get(lwpid); + if (searchThread == nullptr) { + return ErrorCode::SRCH; + } + } + + auto namelen = std::strlen(searchThread->name); + + if (namelen >= buflen) { + return ErrorCode::INVAL; + } + + ORBIS_RET_ON_ERROR(uwriteRaw(buf, searchThread->name, namelen)); + return {}; } orbis::SysResult orbis::sys_set_gpo(Thread *thread /* TODO */) { return ErrorCode::NOSYS; @@ -1095,10 +1184,16 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid, return sysIpmiSendConnectResult(thread, result, kid, params, paramsSz); case 0x232: return sysIpmiSessionRespondSync(thread, result, kid, params, paramsSz); + case 0x251: + return sysIpmiClientGetMessage(thread, result, kid, params, paramsSz); case 0x252: return sysIpmiClientTryGetMessage(thread, result, kid, params, paramsSz); + case 0x254: + return sysIpmiSessionTrySendMessage(thread, result, kid, params, paramsSz); case 0x302: return sysIpmiSessionGetClientPid(thread, result, kid, params, paramsSz); + case 0x310: + return sysIpmiClientDisconnect(thread, result, kid, params, paramsSz); case 0x320: return sysIpmiClientInvokeSyncMethod(thread, result, kid, params, paramsSz); case 0x400: diff --git a/orbis-kernel/src/sys/sys_uipc.cpp b/orbis-kernel/src/sys/sys_uipc.cpp index 3f616da8d..6918ea5e4 100644 --- a/orbis-kernel/src/sys/sys_uipc.cpp +++ b/orbis-kernel/src/sys/sys_uipc.cpp @@ -1,10 +1,7 @@ -#include "pipe.hpp" #include "sys/sysproto.hpp" #include "uio.hpp" #include "utils/Logs.hpp" -#include #include -#include orbis::SysResult orbis::sys_socket(Thread *thread, sint domain, sint type, sint protocol) { @@ -24,37 +21,89 @@ orbis::SysResult orbis::sys_socket(Thread *thread, sint domain, sint type, } return ErrorCode::NOSYS; } + orbis::SysResult orbis::sys_bind(Thread *thread, sint s, caddr_t name, sint namelen) { - ORBIS_LOG_ERROR(__FUNCTION__, s, name, namelen); - return {}; + // ORBIS_LOG_ERROR(__FUNCTION__, s, name, namelen); + + auto file = thread->tproc->fileDescriptors.get(s); + if (file == nullptr) { + return ErrorCode::BADF; + } + + if (auto bind = file->ops->bind) { + return bind(file.get(), ptr(name), namelen, thread); + } + + return ErrorCode::NOTSUP; } + orbis::SysResult orbis::sys_listen(Thread *thread, sint s, sint backlog) { ORBIS_LOG_ERROR(__FUNCTION__, s, backlog); - return {}; + auto file = thread->tproc->fileDescriptors.get(s); + if (file == nullptr) { + return ErrorCode::BADF; + } + + if (auto listen = file->ops->listen) { + return listen(file.get(), backlog, thread); + } + + return ErrorCode::NOTSUP; } + orbis::SysResult orbis::sys_accept(Thread *thread, sint s, - ptr from, + ptr from, ptr fromlenaddr) { ORBIS_LOG_ERROR(__FUNCTION__, s, from, fromlenaddr); - std::this_thread::sleep_for(std::chrono::days(1)); - return SysResult::notAnError(ErrorCode::WOULDBLOCK); + auto file = thread->tproc->fileDescriptors.get(s); + if (file == nullptr) { + return ErrorCode::BADF; + } + + if (auto accept = file->ops->accept) { + return accept(file.get(), from, fromlenaddr, thread); + } + + return ErrorCode::NOTSUP; } + orbis::SysResult orbis::sys_connect(Thread *thread, sint s, caddr_t name, sint namelen) { - return ErrorCode::NOSYS; + auto file = thread->tproc->fileDescriptors.get(s); + if (file == nullptr) { + return ErrorCode::BADF; + } + + if (auto connect = file->ops->connect) { + return connect(file.get(), ptr(name), namelen, thread); + } + + return ErrorCode::NOTSUP; } orbis::SysResult orbis::sys_socketpair(Thread *thread, sint domain, sint type, sint protocol, ptr rsv) { - ORBIS_LOG_ERROR(__FUNCTION__, domain, type, protocol, rsv); + ORBIS_LOG_TODO(__FUNCTION__, domain, type, protocol, rsv); + if (auto socketpair = thread->tproc->ops->socketpair) { + Ref a; + Ref b; + auto result = socketpair(thread, domain, type, protocol, &a, &b); - auto pipe = createPipe(); - auto a = thread->tproc->fileDescriptors.insert(pipe); - auto b = thread->tproc->fileDescriptors.insert(pipe); - if (auto errc = uwrite(rsv, a); errc != ErrorCode{}) { - return errc; + if (result.isError()) { + return result; + } + + auto aFd = thread->tproc->fileDescriptors.insert(a); + auto bFd = thread->tproc->fileDescriptors.insert(b); + + if (auto errc = uwrite(rsv, aFd); errc != ErrorCode{}) { + return errc; + } + + return uwrite(rsv + 1, bFd); } - return uwrite(rsv + 1, b); + + return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_sendto(Thread *thread, sint s, caddr_t buf, size_t len, sint flags, caddr_t to, @@ -67,54 +116,82 @@ orbis::SysResult orbis::sys_sendmsg(Thread *thread, sint s, } orbis::SysResult orbis::sys_recvfrom(Thread *thread, sint s, caddr_t buf, size_t len, sint flags, - ptr from, + ptr from, ptr fromlenaddr) { - auto pipe = thread->tproc->fileDescriptors.get(s).cast(); - if (pipe == nullptr) { - return ErrorCode::INVAL; + auto file = thread->tproc->fileDescriptors.get(s); + if (file == nullptr) { + return ErrorCode::BADF; } - std::lock_guard lock(pipe->mtx); - IoVec io = { - .base = buf, - .len = len, - }; - Uio uio{ - .iov = &io, - .iovcnt = 1, - .segflg = UioSeg::UserSpace, - .rw = UioRw::Read, - .td = thread, - }; - pipe->ops->read(pipe.get(), &uio, thread); - thread->retval[0] = uio.offset; - return {}; + if (auto recvfrom = file->ops->recvfrom) { + return SysResult::notAnError(recvfrom(file.get(), buf, len, flags, from, fromlenaddr, thread)); + } + + return ErrorCode::NOTSUP; } orbis::SysResult orbis::sys_recvmsg(Thread *thread, sint s, ptr msg, sint flags) { - return ErrorCode::NOSYS; + auto file = thread->tproc->fileDescriptors.get(s); + if (file == nullptr) { + return ErrorCode::BADF; + } + + if (auto recvmsg = file->ops->recvmsg) { + return recvmsg(file.get(), msg, flags, thread); + } + + return ErrorCode::NOTSUP; } orbis::SysResult orbis::sys_shutdown(Thread *thread, sint s, sint how) { - return ErrorCode::NOSYS; + auto file = thread->tproc->fileDescriptors.get(s); + if (file == nullptr) { + return ErrorCode::BADF; + } + + if (auto shutdown = file->ops->shutdown) { + return shutdown(file.get(), how, thread); + } + + return ErrorCode::NOTSUP; } orbis::SysResult orbis::sys_setsockopt(Thread *thread, sint s, sint level, sint name, caddr_t val, sint valsize) { ORBIS_LOG_TODO(__FUNCTION__, s, level, name, val, valsize); - return {}; + auto file = thread->tproc->fileDescriptors.get(s); + if (file == nullptr) { + return ErrorCode::BADF; + } + + if (auto setsockopt = file->ops->setsockopt) { + return setsockopt(file.get(), level, name, val, valsize, thread); + } + + return ErrorCode::NOTSUP; } orbis::SysResult orbis::sys_getsockopt(Thread *thread, sint s, sint level, sint name, caddr_t val, ptr avalsize) { ORBIS_LOG_TODO(__FUNCTION__, s, level, name, val, avalsize); - return {}; + auto file = thread->tproc->fileDescriptors.get(s); + if (file == nullptr) { + return ErrorCode::BADF; + } + + if (auto getsockopt = file->ops->getsockopt) { + return getsockopt(file.get(), level, name, val, avalsize, thread); + } + + return ErrorCode::NOTSUP; } orbis::SysResult orbis::sys_getsockname(Thread *thread, sint fdes, - ptr asa, + ptr asa, ptr alen) { - return ErrorCode::NOSYS; + // return uwrite(alen, sizeof(SockAddr)); + ORBIS_LOG_TODO(__FUNCTION__); + return {}; } orbis::SysResult orbis::sys_getpeername(Thread *thread, sint fdes, - ptr asa, + ptr asa, ptr alen) { return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_vfs.cpp b/orbis-kernel/src/sys/sys_vfs.cpp index 61ff008f6..cc476579f 100644 --- a/orbis-kernel/src/sys/sys_vfs.cpp +++ b/orbis-kernel/src/sys/sys_vfs.cpp @@ -2,19 +2,52 @@ #include "sys/sysproto.hpp" #include "utils/Logs.hpp" #include +#include orbis::SysResult orbis::sys_sync(Thread *thread) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_quotactl(Thread *thread, ptr path, sint cmd, sint uid, caddr_t arg) { return ErrorCode::NOSYS; } + +namespace orbis { +struct statfs { + char pad[0x118]; + char f_fstypename[16]; /* filesystem type name */ + char f_mntfromname[88]; /* mounted filesystem */ + char f_mntonname[88]; /* directory on which mounted */ +}; +} // namespace orbis + orbis::SysResult orbis::sys_statfs(Thread *thread, ptr path, ptr buf) { - return ErrorCode::NOSYS; + if (buf == 0) { + thread->retval[0] = 1; + return {}; + } + + std::strncpy(buf->f_fstypename, "exfatfs", sizeof(buf->f_fstypename)); + std::strncpy(buf->f_mntfromname, "/dev/super-hdd", + sizeof(buf->f_mntfromname)); + std::strncpy(buf->f_mntonname, "/system/", sizeof(buf->f_mntonname)); + + thread->retval[0] = 1; + return {}; } orbis::SysResult orbis::sys_fstatfs(Thread *thread, sint fd, ptr buf) { - return ErrorCode::NOSYS; + if (buf == 0) { + thread->retval[0] = 1; + return {}; + } + + std::strncpy(buf->f_fstypename, "exfatfs", sizeof(buf->f_fstypename)); + std::strncpy(buf->f_mntfromname, "/dev/super-hdd", + sizeof(buf->f_mntfromname)); + std::strncpy(buf->f_mntonname, "/system/", sizeof(buf->f_mntonname)); + + thread->retval[0] = 1; + return {}; } orbis::SysResult orbis::sys_getfsstat(Thread *thread, ptr buf, slong bufsize, sint flags) { @@ -231,7 +264,7 @@ orbis::SysResult orbis::sys_fchflags(Thread *thread, sint fd, sint flags) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_chmod(Thread *thread, ptr path, sint mode) { - return ErrorCode::NOSYS; + return {}; } orbis::SysResult orbis::sys_fchmodat(Thread *thread, sint fd, ptr path, mode_t mode, sint flag) { @@ -353,7 +386,7 @@ orbis::SysResult orbis::sys_getdirentries(Thread *thread, sint fd, auto next = std::min(file->dirEntries.size(), pos + rmax); file->nextOff = next * sizeof(orbis::Dirent); SysResult result{}; - result = uwrite((orbis::Dirent *)buf, entries + pos, next - pos); + result = uwrite(ptr(buf), entries + pos, next - pos); if (result.isError()) return result; diff --git a/rpcsx-gpu/main.cpp b/rpcsx-gpu/main.cpp index 7f5cfcf52..32faa41cb 100644 --- a/rpcsx-gpu/main.cpp +++ b/rpcsx-gpu/main.cpp @@ -23,7 +23,7 @@ #include // TODO: make in optional // TODO -extern void *g_rwMemory; +// extern void *g_rwMemory; extern std::size_t g_memorySize; extern std::uint64_t g_memoryBase; extern amdgpu::RemoteMemory g_hostMemory; @@ -739,16 +739,36 @@ int main(int argc, const char *argv[]) { return 1; } + int dmemFd[3]; + + for (std::size_t i = 0; i < std::size(dmemFd); ++i) { + auto path = "/dev/shm/rpcsx-dmem-" + std::to_string(i); + if (!std::filesystem::exists(path)) { + std::printf("Waiting for dmem %zu\n", i); + while (!std::filesystem::exists(path)) { + std::this_thread::sleep_for(std::chrono::milliseconds(300)); + } + } + + dmemFd[i] = ::shm_open(("/rpcsx-dmem-" + std::to_string(i)).c_str(), O_RDWR, + S_IRUSR | S_IWUSR); + + if (dmemFd[i] < 0) { + std::printf("failed to open dmem shared memory %zu\n", i); + return 1; + } + } + struct stat memoryStat; ::fstat(memoryFd, &memoryStat); amdgpu::RemoteMemory memory{(char *)::mmap( nullptr, memoryStat.st_size, PROT_NONE, MAP_SHARED, memoryFd, 0)}; - extern void *g_rwMemory; + // extern void *g_rwMemory; g_memorySize = memoryStat.st_size; g_memoryBase = 0x40000; - g_rwMemory = ::mmap(nullptr, g_memorySize, PROT_READ | PROT_WRITE, MAP_SHARED, - memoryFd, 0); + // g_rwMemory = ::mmap(nullptr, g_memorySize, PROT_READ | PROT_WRITE, MAP_SHARED, + // memoryFd, 0); g_hostMemory = memory; @@ -997,6 +1017,16 @@ int main(int argc, const char *argv[]) { break; } + case amdgpu::bridge::CommandId::MapDmem: { + auto addr = g_hostMemory.getPointer(cmd.mapDmem.address); + auto mapping = ::mmap(addr, cmd.mapDmem.size, + PROT_READ | PROT_WRITE /*TODO: cmd.mapDmem.prot >> 4*/, + MAP_FIXED | MAP_SHARED, dmemFd[cmd.mapDmem.dmemIndex], + cmd.mapDmem.offset); + device.handleProtectMemory(cmd.mapDmem.address, cmd.mapDmem.size, 0x33 /*TODO: cmd.mapDmem.prot*/); + break; + } + default: util::unreachable("Unexpected command id %u\n", (unsigned)cmd.id); } diff --git a/rpcsx-os/CMakeLists.txt b/rpcsx-os/CMakeLists.txt index 93b70f0aa..8f68f0935 100644 --- a/rpcsx-os/CMakeLists.txt +++ b/rpcsx-os/CMakeLists.txt @@ -41,6 +41,8 @@ add_executable(rpcsx-os iodev/devstat.cpp iodev/devact.cpp iodev/devctl.cpp + iodev/uvd.cpp + iodev/vce.cpp main.cpp backtrace.cpp diff --git a/rpcsx-os/io-device.cpp b/rpcsx-os/io-device.cpp index b73f7a939..d341bfd9a 100644 --- a/rpcsx-os/io-device.cpp +++ b/rpcsx-os/io-device.cpp @@ -1,26 +1,36 @@ #include "io-device.hpp" +#include "align.hpp" #include "orbis/KernelAllocator.hpp" +#include "orbis/SocketAddress.hpp" #include "orbis/file.hpp" +#include "orbis/pipe.hpp" #include "orbis/stat.hpp" +#include "orbis/thread/Process.hpp" +#include "orbis/thread/Thread.hpp" #include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" +#include "vfs.hpp" #include "vm.hpp" #include #include #include #include +#include #include #include #include #include #include #include +#include +#include #include +#include #include struct HostFile : orbis::File { - int hostFd = -1; bool closeOnExit = true; + bool alignTruncate = false; ~HostFile() { if (hostFd > 0 && closeOnExit) { @@ -31,7 +41,11 @@ struct HostFile : orbis::File { struct SocketFile : orbis::File { orbis::utils::kstring name; - int hostFd = -1; + int dom = -1; + int type = -1; + int prot = -1; + + orbis::kmap> options; ~SocketFile() { if (hostFd > 0) { @@ -40,24 +54,6 @@ struct SocketFile : orbis::File { } }; -struct HostFsDevice : IoDevice { - orbis::kstring hostPath; - - explicit HostFsDevice(orbis::kstring path) : hostPath(std::move(path)) {} - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; - orbis::ErrorCode unlink(const char *path, bool recursive, - orbis::Thread *thread) override; - orbis::ErrorCode createSymlink(const char *target, const char *linkPath, - orbis::Thread *thread) override; - orbis::ErrorCode mkdir(const char *path, int mode, - orbis::Thread *thread) override; - orbis::ErrorCode rmdir(const char *path, orbis::Thread *thread) override; - orbis::ErrorCode rename(const char *from, const char *to, - orbis::Thread *thread) override; -}; - static orbis::ErrorCode convertErrc(std::errc errc) { if (errc == std::errc{}) { return {}; @@ -252,57 +248,22 @@ orbis::ErrorCode convertErrno() { return orbis::ErrorCode::IO; } -static orbis::ErrorCode host_read(orbis::File *file, orbis::Uio *uio, - orbis::Thread *) { - auto hostFile = static_cast(file); - if (!hostFile->dirEntries.empty()) - return orbis::ErrorCode::ISDIR; - +static orbis::ErrorCode host_fd_read(int hostFd, orbis::Uio *uio) { std::vector vec; for (auto entry : std::span(uio->iov, uio->iovcnt)) { vec.push_back({.iov_base = entry.base, .iov_len = entry.len}); } - ssize_t cnt = 0; - if (hostFile->hostFd == 0) { - for (auto io : vec) { - cnt += ::read(hostFile->hostFd, io.iov_base, io.iov_len); - - if (cnt != io.iov_len) { - break; - } - } - } else { - cnt = ::preadv(hostFile->hostFd, vec.data(), vec.size(), uio->offset); - } - if (cnt < 0) { - return convertErrno(); - } - - uio->resid -= cnt; - uio->offset += cnt; - return {}; -} - -static orbis::ErrorCode host_write(orbis::File *file, orbis::Uio *uio, - orbis::Thread *) { - auto hostFile = static_cast(file); - if (!hostFile->dirEntries.empty()) - return orbis::ErrorCode::ISDIR; - - std::vector vec; - for (auto entry : std::span(uio->iov, uio->iovcnt)) { - vec.push_back({.iov_base = entry.base, .iov_len = entry.len}); - } - - ssize_t cnt = - ::pwritev(hostFile->hostFd, vec.data(), vec.size(), uio->offset); - + auto cnt = ::preadv(hostFd, vec.data(), vec.size(), uio->offset); if (cnt < 0) { + cnt = 0; for (auto io : vec) { - auto result = ::write(hostFile->hostFd, io.iov_base, io.iov_len); + auto result = ::read(hostFd, io.iov_base, io.iov_len); if (result < 0) { - return convertErrno(); + if (cnt == 0) { + return convertErrno(); + } + break; } cnt += result; @@ -318,6 +279,58 @@ static orbis::ErrorCode host_write(orbis::File *file, orbis::Uio *uio, return {}; } +static orbis::ErrorCode host_fd_write(int hostFd, orbis::Uio *uio) { + std::vector vec; + for (auto entry : std::span(uio->iov, uio->iovcnt)) { + vec.push_back({.iov_base = entry.base, .iov_len = entry.len}); + } + + ssize_t cnt = ::pwritev(hostFd, vec.data(), vec.size(), uio->offset); + + if (cnt < 0) { + cnt = 0; + + for (auto io : vec) { + auto result = ::write(hostFd, io.iov_base, io.iov_len); + if (result < 0) { + if (cnt == 0) { + return convertErrno(); + } + + break; + } + + cnt += result; + + if (cnt != io.iov_len) { + break; + } + } + } + + uio->resid -= cnt; + uio->offset += cnt; + return {}; +} + +static orbis::ErrorCode host_read(orbis::File *file, orbis::Uio *uio, + orbis::Thread *) { + auto hostFile = static_cast(file); + if (!hostFile->dirEntries.empty()) + return orbis::ErrorCode::ISDIR; + + return host_fd_read(hostFile->hostFd, uio); +} + +static orbis::ErrorCode host_write(orbis::File *file, orbis::Uio *uio, + orbis::Thread *) { + auto hostFile = static_cast(file); + if (!hostFile->dirEntries.empty()) + return orbis::ErrorCode::ISDIR; + + return host_fd_write(hostFile->hostFd, uio); +} + static orbis::ErrorCode host_mmap(orbis::File *file, void **address, std::uint64_t size, std::int32_t prot, std::int32_t flags, std::int64_t offset, @@ -388,15 +401,15 @@ static orbis::ErrorCode host_stat(orbis::File *file, orbis::Stat *sb, static orbis::ErrorCode host_truncate(orbis::File *file, std::uint64_t len, orbis::Thread *thread) { auto hostFile = static_cast(file); - if (!hostFile->dirEntries.empty()) + if (!hostFile->dirEntries.empty()) { return orbis::ErrorCode::ISDIR; - - // hack for audio control shared memory - std::uint64_t realLen = len; - if (len == 3880) { - realLen = 0x10000; } - if (::ftruncate(hostFile->hostFd, realLen)) { + + if (hostFile->alignTruncate) { + len = utils::alignUp(len, rx::vm::kPageSize); + } + + if (::ftruncate(hostFile->hostFd, len)) { return convertErrno(); } @@ -410,6 +423,221 @@ static orbis::ErrorCode socket_ioctl(orbis::File *file, std::uint64_t request, return {}; } +static orbis::ErrorCode socket_read(orbis::File *file, orbis::Uio *uio, + orbis::Thread *) { + auto socket = static_cast(file); + + if (socket->hostFd < 0) { + while (true) { + std::this_thread::sleep_for(std::chrono::days(1)); + } + return orbis::ErrorCode::INVAL; + } + + return host_fd_read(socket->hostFd, uio); +} + +static orbis::ErrorCode socket_write(orbis::File *file, orbis::Uio *uio, + orbis::Thread *) { + auto socket = static_cast(file); + + if (socket->hostFd < 0) { + for (auto io : std::span(uio->iov, uio->iovcnt)) { + uio->offset += io.len; + } + return {}; + } + + return host_fd_write(socket->hostFd, uio); +} + +static orbis::ErrorCode socket_bind(orbis::File *file, + orbis::SocketAddress *address, + std::size_t addressLen, + orbis::Thread *thread) { + auto socket = static_cast(file); + + if (socket->hostFd < 0) { + return {}; + } + + if (address->family == 1) { + auto vfsPath = std::string_view((const char *)address->data); + auto [device, path] = rx::vfs::get(vfsPath); + + if (auto hostDev = device.cast()) { + auto socketPath = std::filesystem::path(hostDev->hostPath); + socketPath /= path; + + if (socketPath.native().size() >= sizeof(sockaddr_un::sun_path)) { + return orbis::ErrorCode::NAMETOOLONG; + } + + ORBIS_LOG_ERROR(__FUNCTION__, vfsPath, socketPath.native()); + + sockaddr_un un{.sun_family = AF_UNIX}; + std::strncpy(un.sun_path, socketPath.c_str(), sizeof(un.sun_path)); + if (::bind(socket->hostFd, reinterpret_cast<::sockaddr *>(&un), + sizeof(un)) < 0) { + return convertErrno(); + } + + return {}; + } + } + + return orbis::ErrorCode::NOTSUP; +} + +static orbis::ErrorCode socket_listen(orbis::File *file, int backlog, + orbis::Thread *thread) { + auto socket = static_cast(file); + + if (socket->hostFd < 0) { + return {}; + } + + if (::listen(socket->hostFd, backlog) < 0) { + return convertErrno(); + } + + return {}; +} + +static orbis::ErrorCode socket_accept(orbis::File *file, + orbis::SocketAddress *address, + std::uint32_t *addressLen, + orbis::Thread *thread) { + auto socket = static_cast(file); + + if (socket->hostFd < 0) { + ORBIS_LOG_ERROR(__FUNCTION__, socket->name, "wait forever"); + + while (true) { + std::this_thread::sleep_for(std::chrono::days(1)); + } + } + + ORBIS_LOG_ERROR(__FUNCTION__, socket->name); + + if (socket->dom == 1 && socket->type == 1 && socket->prot == 0) { + sockaddr_un un{.sun_family = AF_UNIX}; + socklen_t len = sizeof(un); + int result = + ::accept(socket->hostFd, reinterpret_cast(&un), &len); + + if (result < 0) { + return convertErrno(); + } + + if (addressLen && address) { + *addressLen = 2; + } + + auto guestSocket = wrapSocket(result, "", 1, 1, 0); + auto guestFd = thread->tproc->fileDescriptors.insert(guestSocket); + thread->retval[0] = guestFd; + ORBIS_LOG_ERROR(__FUNCTION__, socket->name, guestFd); + return {}; + } + + return orbis::ErrorCode::NOTSUP; +} + +static orbis::ErrorCode socket_connect(orbis::File *file, + orbis::SocketAddress *address, + std::uint32_t addressLen, + orbis::Thread *thread) { + auto socket = static_cast(file); + + if (socket->hostFd < 0) { + return orbis::ErrorCode::CONNREFUSED; + } + + if (address->family == 1) { + auto vfsPath = std::string_view((const char *)address->data); + auto [device, path] = rx::vfs::get(vfsPath); + + if (auto hostDev = device.cast()) { + auto socketPath = std::filesystem::path(hostDev->hostPath); + socketPath /= path; + ORBIS_LOG_ERROR(__FUNCTION__, vfsPath, socketPath.native()); + + if (socketPath.native().size() >= sizeof(sockaddr_un::sun_path)) { + return orbis::ErrorCode::NAMETOOLONG; + } + + sockaddr_un un{.sun_family = AF_UNIX}; + std::strncpy(un.sun_path, socketPath.c_str(), sizeof(un.sun_path)); + if (::connect(socket->hostFd, reinterpret_cast<::sockaddr *>(&un), + sizeof(un)) < 0) { + return convertErrno(); + } + + return {}; + } + } + + return orbis::ErrorCode::NOTSUP; +} + +orbis::ErrorCode socket_setsockopt(orbis::File *file, orbis::sint level, + orbis::sint name, const void *val, + orbis::sint valsize, orbis::Thread *thread) { + ORBIS_LOG_ERROR(__FUNCTION__, level, name); + auto socket = static_cast(file); + orbis::kvector option(valsize); + std::memcpy(option.data(), val, valsize); + socket->options[name] = std::move(option); + return {}; +} + +orbis::ErrorCode socket_getsockopt(orbis::File *file, orbis::sint level, + orbis::sint name, void *val, + orbis::sint *avalsize, + orbis::Thread *thread) { + ORBIS_LOG_ERROR(__FUNCTION__, level, name); + auto socket = static_cast(file); + auto &option = socket->options[name]; + if (option.size() > *avalsize) { + return orbis::ErrorCode::INVAL; + } + + *avalsize = option.size(); + std::memcpy(val, option.data(), option.size()); + return {}; +} + +orbis::ErrorCode socket_recvfrom(orbis::File *file, void *buf, + orbis::size_t len, orbis::sint flags, + orbis::SocketAddress *from, + orbis::uint32_t *fromlenaddr, + orbis::Thread *thread) { + auto socket = static_cast(file); + + if (socket->hostFd < 0) { + return orbis::ErrorCode::CONNREFUSED; + } + + if (socket->dom == 1 && socket->type == 1 && socket->prot == 0) { + auto count = ::recvfrom(socket->hostFd, buf, len, flags, nullptr, nullptr); + if (count < 0) { + return convertErrno(); + } + thread->retval[0] = count; + + if (from && fromlenaddr) { + from->len = 0; + from->family = 1; + *fromlenaddr = 2; + } + + return {}; + } + + return orbis::ErrorCode::NOTSUP; +} + static const orbis::FileOps hostOps = { .read = host_read, .write = host_write, @@ -420,29 +648,55 @@ static const orbis::FileOps hostOps = { static const orbis::FileOps socketOps = { .ioctl = socket_ioctl, + .read = socket_read, + .write = socket_write, + .bind = socket_bind, + .listen = socket_listen, + .accept = socket_accept, + .connect = socket_connect, + .recvfrom = socket_recvfrom, + .setsockopt = socket_setsockopt, + .getsockopt = socket_getsockopt, }; -IoDevice *createHostIoDevice(orbis::kstring hostPath) { - while (hostPath.size() > 1 && hostPath.ends_with("/")) { +IoDevice *createHostIoDevice(orbis::kstring hostPath, + orbis::kstring virtualPath) { + while (hostPath.size() > 0 && hostPath.ends_with("/")) { hostPath.resize(hostPath.size() - 1); } - return orbis::knew(std::move(hostPath)); + return orbis::knew(std::move(hostPath), std::move(virtualPath)); +} + +orbis::Ref wrapSocket(int hostFd, orbis::kstring name, int dom, + int type, int prot) { + auto s = orbis::knew(); + s->name = std::move(name); + s->dom = dom; + s->type = type; + s->prot = prot; + s->hostFd = hostFd; + s->ops = &socketOps; + return s; } orbis::ErrorCode createSocket(orbis::Ref *file, orbis::kstring name, int dom, int type, int prot) { - auto fd = ::socket(dom, type, prot); - // if (fd < 0) { - // return convertErrno(); - // } + // ORBIS_LOG_ERROR(__FUNCTION__, name, dom, type, prot); + // *file = orbis::createPipe(); + // return {}; + int fd = -1; - auto s = orbis::knew(); - s->name = std::move(name); - s->hostFd = fd; - s->ops = &socketOps; - *file = s; + if (dom == 1 && type == 1 && prot == 0) { + fd = ::socket(dom, type, prot); + + if (fd < 0) { + return convertErrno(); + } + } + + *file = wrapSocket(fd, std::move(name), dom, type, prot); return {}; } @@ -502,36 +756,49 @@ orbis::ErrorCode HostFsDevice::open(orbis::Ref *file, if (hostFd < 0) { auto error = convertErrno(); - ORBIS_LOG_ERROR("host_open failed", path, realPath, error); + ORBIS_LOG_ERROR("host_open failed", path, realPath.c_str(), error); return error; } // Assume the file is a directory and try to read direntries orbis::utils::kvector dirEntries; + char hostEntryBuffer[sizeof(dirent64) * 4]; while (true) { - ::dirent64 hostEntry{}; - auto r = getdents64(hostFd, &hostEntry, sizeof(hostEntry)); + auto r = getdents64(hostFd, hostEntryBuffer, sizeof(hostEntryBuffer)); if (r <= 0) break; - if (hostEntry.d_name == std::string_view("..") || - hostEntry.d_name == std::string_view(".")) { - continue; - } + std::size_t offset = 0; - auto &entry = dirEntries.emplace_back(); - entry.fileno = dirEntries.size(); // TODO - entry.reclen = sizeof(entry); - entry.namlen = std::strlen(hostEntry.d_name); - std::strncpy(entry.name, hostEntry.d_name, sizeof(entry.name)); - if (hostEntry.d_type == DT_REG) - entry.type = orbis::kDtReg; - else if (hostEntry.d_type == DT_DIR || hostEntry.d_type == DT_LNK) - entry.type = orbis::kDtDir; // Assume symlinks to be dirs - else { - ORBIS_LOG_ERROR("host_open: unknown directory entry d_type", realPath, - hostEntry.d_name, hostEntry.d_type); - dirEntries.pop_back(); + while (offset < r) { + ::dirent64 *entryPtr = + reinterpret_cast(hostEntryBuffer + offset); + offset += entryPtr->d_reclen; + + if (entryPtr->d_name == std::string_view("..") || + entryPtr->d_name == std::string_view(".") || + entryPtr->d_name == std::string_view(".rpcsx")) { + continue; + } + + // auto entryPath = (std::filesystem::path(virtualPath) / path / + // entryPtr->d_name).lexically_normal().string(); + std::string entryPath = entryPtr->d_name; + + auto &entry = dirEntries.emplace_back(); + entry.fileno = dirEntries.size(); // TODO + entry.reclen = sizeof(entry); + entry.namlen = entryPath.length(); + std::strncpy(entry.name, entryPath.c_str(), sizeof(entry.name)); + if (entryPtr->d_type == DT_REG) + entry.type = orbis::kDtReg; + else if (entryPtr->d_type == DT_DIR || entryPtr->d_type == DT_LNK) + entry.type = orbis::kDtDir; // Assume symlinks to be dirs + else { + ORBIS_LOG_ERROR("host_open: unknown directory entry d_type", + realPath.c_str(), entryPtr->d_name, entryPtr->d_type); + dirEntries.pop_back(); + } } } @@ -585,11 +852,12 @@ orbis::ErrorCode HostFsDevice::rename(const char *from, const char *to, return convertErrorCode(ec); } -orbis::File *createHostFile(int hostFd, orbis::Ref device) { +orbis::File *createHostFile(int hostFd, orbis::Ref device, bool alignTruncate) { auto newFile = orbis::knew(); newFile->hostFd = hostFd; newFile->ops = &hostOps; newFile->device = device; + newFile->alignTruncate = alignTruncate; return newFile; } diff --git a/rpcsx-os/io-device.hpp b/rpcsx-os/io-device.hpp index 5072bd16e..02679a180 100644 --- a/rpcsx-os/io-device.hpp +++ b/rpcsx-os/io-device.hpp @@ -48,9 +48,29 @@ struct IoDevice : orbis::RcBase { } }; +struct HostFsDevice : IoDevice { + orbis::kstring hostPath; + orbis::kstring virtualPath; + + HostFsDevice(orbis::kstring path, orbis::kstring virtualPath) : hostPath(std::move(path)), virtualPath(std::move(virtualPath)) {} + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override; + orbis::ErrorCode unlink(const char *path, bool recursive, + orbis::Thread *thread) override; + orbis::ErrorCode createSymlink(const char *target, const char *linkPath, + orbis::Thread *thread) override; + orbis::ErrorCode mkdir(const char *path, int mode, + orbis::Thread *thread) override; + orbis::ErrorCode rmdir(const char *path, orbis::Thread *thread) override; + orbis::ErrorCode rename(const char *from, const char *to, + orbis::Thread *thread) override; +}; + orbis::ErrorCode convertErrno(); -IoDevice *createHostIoDevice(orbis::kstring hostPath); +IoDevice *createHostIoDevice(orbis::kstring hostPath, orbis::kstring virtualPath); +orbis::Ref wrapSocket(int hostFd, orbis::kstring name, int dom, int type, int prot); orbis::ErrorCode createSocket(orbis::Ref *file, orbis::kstring name, int dom, int type, int prot); -orbis::File *createHostFile(int hostFd, orbis::Ref device); +orbis::File *createHostFile(int hostFd, orbis::Ref device, bool alignTruncate = false); IoDevice *createFdWrapDevice(int fd); diff --git a/rpcsx-os/io-devices.hpp b/rpcsx-os/io-devices.hpp index bc1328321..d3809e354 100644 --- a/rpcsx-os/io-devices.hpp +++ b/rpcsx-os/io-devices.hpp @@ -40,3 +40,5 @@ IoDevice *createGbaseCharacterDevice(); IoDevice *createDevStatCharacterDevice(); IoDevice *createDevCtlCharacterDevice(); IoDevice *createDevActCharacterDevice(); +IoDevice *createUVDCharacterDevice(); +IoDevice *createVCECharacterDevice(); diff --git a/rpcsx-os/iodev/aout.cpp b/rpcsx-os/iodev/aout.cpp index 53e84e279..deb35a4f8 100644 --- a/rpcsx-os/iodev/aout.cpp +++ b/rpcsx-os/iodev/aout.cpp @@ -1,26 +1,31 @@ #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" #include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" +#include #include #include struct AoutFile : orbis::File {}; static orbis::ErrorCode aout_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { + void *argp, orbis::Thread *thread) { ORBIS_LOG_FATAL("Unhandled aout ioctl", request); if (request == 0xc004500a) { std::this_thread::sleep_for(std::chrono::days(1)); } + thread->where(); return {}; } static orbis::ErrorCode aout_write(orbis::File *file, orbis::Uio *uio, orbis::Thread *) { - uio->resid = 0; + for (auto entry : std::span(uio->iov, uio->iovcnt)) { + uio->offset += entry.len; + } return {}; } @@ -33,9 +38,11 @@ struct AoutDevice : IoDevice { orbis::ErrorCode open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) override { + ORBIS_LOG_FATAL("aout device open", path, flags, mode); auto newFile = orbis::knew(); newFile->ops = &fileOps; newFile->device = this; + thread->where(); *file = newFile; return {}; diff --git a/rpcsx-os/iodev/console.cpp b/rpcsx-os/iodev/console.cpp index 66ac19b90..e480c13c2 100644 --- a/rpcsx-os/iodev/console.cpp +++ b/rpcsx-os/iodev/console.cpp @@ -49,9 +49,10 @@ static orbis::ErrorCode console_write(orbis::File *file, orbis::Uio *uio, auto dev = dynamic_cast(file->device.get()); for (auto vec : std::span(uio->iov, uio->iovcnt)) { + uio->offset += vec.len; ::write(dev->outputFd, vec.base, vec.len); + ::write(2, vec.base, vec.len); } - uio->resid = 0; return {}; } diff --git a/rpcsx-os/iodev/dce.cpp b/rpcsx-os/iodev/dce.cpp index 273bb139d..9316718a4 100644 --- a/rpcsx-os/iodev/dce.cpp +++ b/rpcsx-os/iodev/dce.cpp @@ -207,6 +207,7 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, ORBIS_LOG_NOTICE("dce: UNIMPLEMENTED FlipControl", args->id, args->arg2, args->ptr, args->size); + thread->where(); std::fflush(stdout); //__builtin_trap(); } diff --git a/rpcsx-os/iodev/dmem.cpp b/rpcsx-os/iodev/dmem.cpp index 68615f942..6844037a1 100644 --- a/rpcsx-os/iodev/dmem.cpp +++ b/rpcsx-os/iodev/dmem.cpp @@ -1,11 +1,16 @@ #include "dmem.hpp" +#include "bridge.hpp" #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" +#include "orbis/thread/Process.hpp" #include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" #include "vm.hpp" +#include #include +#include +#include struct DmemFile : public orbis::File {}; @@ -21,18 +26,46 @@ static constexpr auto dmemSize = 8ull * 1024 * 1024 * 1024; // static const std::uint64_t nextOffset = 0; // static const std::uint64_t memBeginAddress = 0xfe0000000; +DmemDevice::~DmemDevice() { + if (shmFd > 0) { + close(shmFd); + } + + shm_unlink(("/rpcsx-dmem-" + std::to_string(index)).c_str()); +} + orbis::ErrorCode DmemDevice::mmap(void **address, std::uint64_t len, std::int32_t prot, std::int32_t flags, std::int64_t directMemoryStart) { - auto result = - rx::vm::map(*address, len, prot, flags, 0, this, directMemoryStart); + if (prot == 0) { + // hack + // fixme: implement protect for pid + prot = rx::vm::kMapProtCpuWrite | rx::vm::kMapProtCpuRead | + rx::vm::kMapProtGpuAll; + } - ORBIS_LOG_WARNING("dmem mmap", index, directMemoryStart, prot, flags, result); + auto result = + rx::vm::map(*address, len, prot, flags, rx::vm::kMapInternalReserveOnly, + this, directMemoryStart); + + ORBIS_LOG_WARNING("dmem mmap", index, directMemoryStart, prot, flags, result, + *address); if (result == (void *)-1) { return orbis::ErrorCode::NOMEM; // TODO } + if (::mmap(result, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, shmFd, + directMemoryStart) == (void *)-1) { + std::abort(); + return orbis::ErrorCode::INVAL; + } + + rx::bridge.sendMapDmem(orbis::g_currentThread->tproc->pid, index, + reinterpret_cast(result), len, prot, + directMemoryStart); + *address = result; + return {}; } @@ -61,6 +94,7 @@ static orbis::ErrorCode dmem_ioctl(orbis::File *file, std::uint64_t request, args->alignment, &args->size); } + case 0xc0288010: // sceKernelAllocateDirectMemoryForMiniApp case 0xc0288011: case 0xc0288001: { // sceKernelAllocateDirectMemory auto args = reinterpret_cast(argp); @@ -69,6 +103,21 @@ static orbis::ErrorCode dmem_ioctl(orbis::File *file, std::uint64_t request, args->alignment, args->memoryType); } + case 0xc018800d: { // transfer budget + return {}; + } + + case 0xc018800f: { // protect memory for pid + struct Args { + std::uint64_t address; + std::uint64_t size; + std::uint32_t pid; // 0 if all + std::uint32_t prot; + }; + return {}; + } + + case 0x80108015: // sceKernelCheckedReleaseDirectMemory case 0x80108002: { // sceKernelReleaseDirectMemory struct Args { std::uint64_t address; @@ -302,5 +351,14 @@ IoDevice *createDmemCharacterDevice(int index) { auto *newDevice = orbis::knew(); newDevice->index = index; newDevice->dmemTotalSize = dmemSize; + auto shmFd = ::shm_open(("/rpcsx-dmem-" + std::to_string(index)).c_str(), + O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + + if (ftruncate(shmFd, dmemSize) < 0) { + ::close(shmFd); + std::abort(); + } + + newDevice->shmFd = shmFd; return newDevice; } diff --git a/rpcsx-os/iodev/dmem.hpp b/rpcsx-os/iodev/dmem.hpp index 77816ae45..9f2ef5655 100644 --- a/rpcsx-os/iodev/dmem.hpp +++ b/rpcsx-os/iodev/dmem.hpp @@ -13,8 +13,11 @@ struct DmemDevice : public IoDevice { orbis::shared_mutex mtx; int index; + int shmFd = -1; std::size_t dmemTotalSize; + ~DmemDevice(); + struct AllocationInfo { std::uint32_t memoryType; diff --git a/rpcsx-os/iodev/gc.cpp b/rpcsx-os/iodev/gc.cpp index 552b00eaa..cd2a8803e 100644 --- a/rpcsx-os/iodev/gc.cpp +++ b/rpcsx-os/iodev/gc.cpp @@ -132,8 +132,9 @@ static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, break; } - case 0xc0048116: { + case 0xc0048116: { // submit done? ORBIS_LOG_ERROR("gc ioctl 0xc0048116", *(std::uint32_t *)argp); + *(std::uint32_t *)argp = 1; thread->where(); break; } diff --git a/rpcsx-os/iodev/notification.cpp b/rpcsx-os/iodev/notification.cpp index 07f6679cd..5300f881d 100644 --- a/rpcsx-os/iodev/notification.cpp +++ b/rpcsx-os/iodev/notification.cpp @@ -72,8 +72,8 @@ static orbis::ErrorCode notification_write(orbis::File *file, orbis::Uio *uio, o auto offset = dev->data.size(); dev->data.resize(offset + vec.len); std::memcpy(dev->data.data(), vec.base, vec.len); + uio->offset += vec.len; } - uio->resid = 0; return {}; } diff --git a/rpcsx-os/iodev/null.cpp b/rpcsx-os/iodev/null.cpp index 201d72a99..66a327348 100644 --- a/rpcsx-os/iodev/null.cpp +++ b/rpcsx-os/iodev/null.cpp @@ -1,6 +1,7 @@ #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/uio.hpp" +#include struct NullDevice : public IoDevice { orbis::ErrorCode open(orbis::Ref *file, const char *path, @@ -11,7 +12,9 @@ struct NullFile : public orbis::File {}; static orbis::ErrorCode null_write(orbis::File *file, orbis::Uio *uio, orbis::Thread *) { - uio->resid = 0; + for (auto entry : std::span(uio->iov, uio->iovcnt)) { + uio->offset += entry.len; + } return {}; } diff --git a/rpcsx-os/iodev/shm.cpp b/rpcsx-os/iodev/shm.cpp index 270c7efe1..c93d84acd 100644 --- a/rpcsx-os/iodev/shm.cpp +++ b/rpcsx-os/iodev/shm.cpp @@ -38,7 +38,6 @@ orbis::ErrorCode ShmDevice::open(orbis::Ref *file, auto name = realShmPath(path); auto realFlags = O_RDWR; // TODO - std::size_t size = 0; if (flags & 0x200) { realFlags |= O_CREAT; } @@ -47,11 +46,8 @@ orbis::ErrorCode ShmDevice::open(orbis::Ref *file, if (fd < 0) { return convertErrno(); } - auto hostFile = createHostFile(fd, this); - if (size != 0) { - hostFile->ops->truncate(hostFile, size, thread); - } + auto hostFile = createHostFile(fd, this, true); *file = hostFile; return {}; } diff --git a/rpcsx-os/iodev/uvd.cpp b/rpcsx-os/iodev/uvd.cpp new file mode 100644 index 000000000..749ed7acd --- /dev/null +++ b/rpcsx-os/iodev/uvd.cpp @@ -0,0 +1,32 @@ +#include "io-device.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/file.hpp" +#include "orbis/utils/Logs.hpp" + +struct UVDFile : orbis::File {}; + +static orbis::ErrorCode uvd_ioctl(orbis::File *file, std::uint64_t request, + void *argp, orbis::Thread *thread) { + + ORBIS_LOG_FATAL("Unhandled uvd ioctl", request); + return {}; +} + +static const orbis::FileOps fileOps = { + .ioctl = uvd_ioctl, +}; + +struct UVDDevice : IoDevice { + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; + + *file = newFile; + return {}; + } +}; + +IoDevice *createUVDCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/vce.cpp b/rpcsx-os/iodev/vce.cpp new file mode 100644 index 000000000..d23450c1e --- /dev/null +++ b/rpcsx-os/iodev/vce.cpp @@ -0,0 +1,45 @@ +#include "io-device.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" +#include "orbis/utils/Logs.hpp" + +struct VCEFile : orbis::File {}; + +static orbis::ErrorCode vce_ioctl(orbis::File *file, std::uint64_t request, + void *argp, orbis::Thread *thread) { + + switch (request) { + case 0xc0048406: + *reinterpret_cast(argp) = 0x700; + return{}; + + case 0x80488401: + auto unkAddress = *reinterpret_cast(argp); + ORBIS_LOG_ERROR(__FUNCTION__, request, unkAddress); + return{}; + } + + ORBIS_LOG_FATAL("Unhandled vce ioctl", request); + thread->where(); + return {}; +} + +static const orbis::FileOps fileOps = { + .ioctl = vce_ioctl, +}; + +struct VCEDevice : IoDevice { + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; + + *file = newFile; + return {}; + } +}; + +IoDevice *createVCECharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/linker.cpp b/rpcsx-os/linker.cpp index a6724491c..0f01a719e 100644 --- a/rpcsx-os/linker.cpp +++ b/rpcsx-os/linker.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -968,7 +969,7 @@ Ref rx::linker::loadModuleFile(std::string_view path, image[2] != std::byte{'L'} || image[3] != std::byte{'F'}) { image = unself(image.data(), image.size()); - std::ofstream("a.out", std::ios::binary) + std::ofstream(std::filesystem::path(path).filename().replace_extension("elf"), std::ios::binary) .write((const char *)image.data(), image.size()); } diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp index 0ebea01f8..802d371d7 100644 --- a/rpcsx-os/main.cpp +++ b/rpcsx-os/main.cpp @@ -9,6 +9,7 @@ #include "thread.hpp" #include "vfs.hpp" #include "vm.hpp" +#include "xbyak/xbyak.h" #include #include @@ -120,7 +121,7 @@ handle_signal(int sig, siginfo_t *info, void *ucontext) { if (g_gpuPid > 0) { // stop gpu thread - ::kill(g_gpuPid, SIGINT); + // ::kill(g_gpuPid, SIGINT); } if (sig != SIGINT) { @@ -314,7 +315,9 @@ static void onSysExit(orbis::Thread *thread, int id, uint64_t *args, std::fprintf(stderr, ") -> Status %d, Value %lx:%lx\n", result.value(), thread->retval[0], thread->retval[1]); - thread->where(); + if (result.isError()) { + thread->where(); + } funlockfile(stderr); } @@ -391,6 +394,8 @@ static void ps4InitDev() { rx::vfs::addDevice("devstat", createDevStatCharacterDevice()); rx::vfs::addDevice("devact", createDevActCharacterDevice()); rx::vfs::addDevice("devctl", createDevCtlCharacterDevice()); + rx::vfs::addDevice("uvd", createUVDCharacterDevice()); + rx::vfs::addDevice("vce", createVCECharacterDevice()); auto shm = createShmDevice(); rx::vfs::addDevice("shm", shm); @@ -532,6 +537,23 @@ ExecEnv ps4CreateExecEnv(orbis::Thread *mainThread, std::abort(); } + for (auto sym : libkernel->symbols) { + if (sym.id == 0xd2f4e7e480cc53d0) { + auto address = (uint64_t)libkernel->base + sym.address; + ::mprotect((void *)utils::alignDown(address, 0x1000), utils::alignUp(sym.size + sym.address, 0x1000), PROT_WRITE); + std::printf("patching sceKernelGetMainSocId\n"); + struct GetMainSocId : Xbyak::CodeGenerator { + GetMainSocId(std::uint64_t address, std::uint64_t size) : Xbyak::CodeGenerator(size, (void *)address) { + mov(eax, 0x710f00); + ret(); + } + } gen{ address, sym.size }; + + ::mprotect((void *)utils::alignDown(address, 0x1000), utils::alignUp(sym.size + sym.address, 0x1000), PROT_READ | PROT_EXEC); + break; + } + } + if (orbis::g_context.fwSdkVersion == 0) { auto moduleParam = reinterpret_cast(libkernel->moduleParam); auto fwSdkVersion = moduleParam // @@ -607,7 +629,7 @@ static void runRpsxGpu() { isRpsxGpuPid(bridgeHeader->pullerPid)) { bridgeHeader->pusherPid = ::getpid(); g_gpuPid = bridgeHeader->pullerPid; - rx::bridge = bridgeHeader; + rx::bridge.header = bridgeHeader; return; } @@ -617,7 +639,7 @@ static void runRpsxGpu() { bridgeHeader = amdgpu::bridge::createShmCommandBuffer(cmdBufferName); } bridgeHeader->pusherPid = ::getpid(); - rx::bridge = bridgeHeader; + rx::bridge.header = bridgeHeader; auto rpcsxGpuPath = getSelfDir() / "rpcsx-gpu"; @@ -686,6 +708,22 @@ struct IpmiServer { return *this; } + IpmiServer &createSyncHandlerStub(std::uint32_t methodId, + std::function handler) { + syncHandlers[methodId] = + [=](std::int32_t &errorCode, std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { + if (!outData.empty()) { + return orbis::ErrorCode::INVAL; + } + + errorCode = handler(); + return {}; + }; + return *this; + } + IpmiServer &createSyncHandler( std::uint32_t methodId, std::function handler) { @@ -693,7 +731,7 @@ struct IpmiServer { [=](std::int32_t &errorCode, std::vector> &outData, const std::vector> &inData) -> orbis::ErrorCode { - if (outData.size() != 1) { + if (outData.size() < 1) { return orbis::ErrorCode::INVAL; } @@ -732,6 +770,34 @@ struct IpmiServer { return *this; } + template + IpmiServer &createSyncHandler( + std::uint32_t methodId, + std::function handler) { + syncHandlers[methodId] = + [=](std::int32_t &errorCode, std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { + if (outData.size() != 1 || inData.size() != 1) { + return orbis::ErrorCode::INVAL; + } + + if (inData[0].size() != sizeof(InT)) { + return orbis::ErrorCode::INVAL; + } + if (outData[0].size() < sizeof(OutT)) { + return orbis::ErrorCode::INVAL; + } + + OutT out; + errorCode = handler(out, *reinterpret_cast(inData[0].data())); + std::memcpy(outData[0].data(), &out, sizeof(out)); + outData[0] = outData[0].subspan(0, sizeof(OutT)); + return {}; + }; + return *this; + } + template IpmiServer & createSyncHandler(std::uint32_t methodId, @@ -811,9 +877,22 @@ struct IpmiServer { session->server->name.c_str(), message->methodId, message->numInData, message->numOutData); + // for (auto in : inData) { + // std::fprintf(stderr, "in %zx\n", in.size()); + // } + + // for (auto out : outData) { + // std::fprintf(stderr, "out %zx\n", out.size()); + // } + std::lock_guard lock(session->mutex); session->messageResponses.push_front({ + // TODO: + // .errorCode = message->numOutData == 0 || + // (message->numOutData == 1 && outData[0].empty()) + // ? 0 + // : -1, .errorCode = 0, .data = orbis::kvector( message->numOutData ? outData[0].size() : 0), @@ -914,6 +993,8 @@ static void createMiniSysCoreObjects(orbis::Process *process) { static void createSysAvControlObjects(orbis::Process *process) { createIpmiServer(process, "SceAvSettingIpc"); + createIpmiServer(process, "SceAvCaptureIpc"); + createEventFlag("SceAvCaptureIpc", 0x121, 0); createEventFlag("SceAvSettingEvf", 0x121, 0xffff00000000); createShm("/SceAvSetting", 0xa02, 0x1a4, 4096); @@ -1009,14 +1090,48 @@ static void createShellCoreObjects(orbis::Process *process) { createIpmiServer(process, "SceNetCtl"); createIpmiServer(process, "SceNpMgrIpc") .createSyncHandler( - 0, [=](void *out, std::uint64_t &size) -> std::int32_t { + 0, + [=](void *out, std::uint64_t &size) -> std::int32_t { std::string_view result = "SceNpMgrEvf"; + if (size < result.size() + 1) { + return 0x8002'0000 + static_cast(orbis::ErrorCode::INVAL); + } std::strncpy((char *)out, result.data(), result.size() + 1); size = result.size() + 1; - orbis::g_context.createEventFlag("SceNpMgrEvf", 0x200, 0); + orbis::g_context.createEventFlag(orbis::kstring(result), 0x200, 0); + return 0; + }) + .createSyncHandlerStub(0xd, [=] -> std::int32_t { return 0; }); + createIpmiServer(process, "SceNpService") + .createSyncHandler(0, [=](void *out, std::uint64_t &size, + std::uint32_t val) { return 0; }) + .createSyncHandler(0xa0001, + [=](void *out, std::uint64_t &size) -> std::int32_t { + if (size < 1) { + return 0x8002'0000 + + static_cast(orbis::ErrorCode::INVAL); + } + size = 1; + *reinterpret_cast(out) = 1; + return 0; + }) + .createSyncHandler(0xa0002, + [=](void *out, std::uint64_t &size) -> std::int32_t { + if (size < 1) { + return 0x8002'0000 + + static_cast(orbis::ErrorCode::INVAL); + } + size = 1; + *reinterpret_cast(out) = 1; + return 0; + }) + .createSyncHandler( + 0xd0000, // sceNpTpipIpcClientGetShmIndex + [=](std::uint32_t &shmIndex, std::uint32_t appId) -> std::int32_t { + shmIndex = 0; return 0; }); - createIpmiServer(process, "SceNpService"); + createIpmiServer(process, "SceNpTrophyIpc"); createIpmiServer(process, "SceNpUdsIpc"); createIpmiServer(process, "SceLibNpRifMgrIpc"); @@ -1033,7 +1148,45 @@ static void createShellCoreObjects(orbis::Process *process) { createIpmiServer(process, "ScePatchChecker"); createIpmiServer(process, "SceMorpheusUpdService"); createIpmiServer(process, "ScePsmSharedDmem"); - createIpmiServer(process, "SceSaveData"); + createIpmiServer(process, "SceSaveData") + .createSyncHandler( + 0x12340001, + [](void *out, std::uint64_t &size) -> std::int32_t { + { + auto [dev, devPath] = rx::vfs::get("/app0"); + if (auto hostFs = dev.cast()) { + std::error_code ec; + auto saveDir = hostFs->hostPath + "/.rpcsx/saves/"; + if (!std::filesystem::exists(saveDir)) { + return 0x8002'0000 + + static_cast(orbis::ErrorCode::NOENT); + } + } + } + std::string_view result = "/saves"; + if (size < result.size() + 1) { + return 0x8002'0000 + static_cast(orbis::ErrorCode::INVAL); + } + std::strncpy((char *)out, result.data(), result.size() + 1); + size = result.size() + 1; + orbis::g_context.createEventFlag(orbis::kstring(result), 0x200, 0); + return 0; + }) + .createSyncHandler( + 0x12340002, [](void *out, std::uint64_t &size) -> std::int32_t { + { + auto [dev, devPath] = rx::vfs::get("/app0"); + if (auto hostFs = dev.cast()) { + std::error_code ec; + auto saveDir = hostFs->hostPath + "/.rpcsx/saves/"; + std::filesystem::create_directories(saveDir, ec); + rx::vfs::mount("/saves/", + createHostIoDevice(saveDir, "/saves/")); + } + } + return 0; + }); + createIpmiServer(process, "SceStickerCoreServer"); createIpmiServer(process, "SceDbRecoveryShellCore"); createIpmiServer(process, "SceUserService") @@ -1096,6 +1249,8 @@ static void createShellCoreObjects(orbis::Process *process) { createEventFlag("SceLncUtilAppStatus1", 0x100, 0); createEventFlag("SceAppMessaging1", 0x120, 1); createEventFlag("SceShellCoreUtil1", 0x120, 0x3f8c); + createEventFlag("SceNpScoreIpc_" + fmtHex(process->pid), 0x120, 0); + createEventFlag("/vmicDdEvfAin", 0x120, 0); createSemaphore("SceAppMessaging1", 0x101, 1, 0x7fffffff); createSemaphore("SceLncSuspendBlock1", 0x101, 1, 10000); @@ -1144,7 +1299,7 @@ static orbis::SysResult launchDaemon(orbis::Thread *thread, std::string path, }; process->authInfo = { - .unk0 = 0x3100000000000001, + .unk0 = 0x380000000000000f, .caps = { -1ul, @@ -1207,6 +1362,8 @@ static orbis::SysResult launchDaemon(orbis::Thread *thread, std::string path, thread->tproc->processParam = executableModule->processParam; thread->tproc->processParamSize = executableModule->processParamSize; + g_traceSyscalls = false; + thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteExec); std::thread([&] { @@ -1260,8 +1417,9 @@ int main(int argc, const char *argv[]) { return 1; } - rx::vfs::mount(argv[argIndex + 2], - createHostIoDevice(argv[argIndex + 1])); + rx::vfs::mount( + argv[argIndex + 2], + createHostIoDevice(argv[argIndex + 1], argv[argIndex + 2])); argIndex += 3; continue; } @@ -1323,7 +1481,7 @@ int main(int argc, const char *argv[]) { // rx::vm::printHostStats(); orbis::g_context.allocatePid(); auto initProcess = orbis::g_context.createProcess(asRoot ? 1 : 10); - pthread_setname_np(pthread_self(), "10.MAINTHREAD"); + // pthread_setname_np(pthread_self(), "10.MAINTHREAD"); std::thread{[] { pthread_setname_np(pthread_self(), "Bridge"); @@ -1400,7 +1558,7 @@ int main(int argc, const char *argv[]) { if (isSystem) { amdgpu::bridge::expGpuPid = 50001; initProcess->authInfo = { - .unk0 = 0x3100000000000001, + .unk0 = 0x380000000000000f, .caps = { -1ul, @@ -1482,6 +1640,9 @@ int main(int argc, const char *argv[]) { createGnmCompositorObjects(initProcess); createShellCoreObjects(initProcess); + createIpmiServer(initProcess, "SceCdlgRichProf"); // ? + initProcess->cwd = "/app0/"; + launchDaemon(mainThread, "/system/sys/orbis_audiod.elf", {"/system/sys/orbis_audiod.elf"}, {}); status = ps4Exec(mainThread, execEnv, std::move(executableModule), diff --git a/rpcsx-os/ops.cpp b/rpcsx-os/ops.cpp index ada8f23a5..41889464c 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx-os/ops.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -356,6 +357,26 @@ orbis::SysResult socket(orbis::Thread *thread, orbis::ptr name, return createSocket(file, name ? name : "", domain, type, protocol); } +orbis::SysResult socketPair(orbis::Thread *thread, orbis::sint domain, + orbis::sint type, orbis::sint protocol, + Ref *a, Ref *b) { + + if (domain == 1 && type == 1 && protocol == 0) { + int fds[2]; + if (::socketpair(domain, type, protocol, fds)) { + return convertErrno(); + } + + *a = wrapSocket(fds[0], "", domain, type, protocol); + *b = wrapSocket(fds[1], "", domain, type, protocol); + } + + auto result = wrapSocket(-1, "", domain, type, protocol); + *a = result; + *b = result; + return {}; +} + orbis::SysResult shm_unlink(orbis::Thread *thread, const char *path) { auto dev = static_cast(orbis::g_context.shmDevice.get()); return dev->unlink(path, false, thread); @@ -879,6 +900,7 @@ ProcessOps rx::procOpsTable = { .blockpool_map = blockpool_map, .blockpool_unmap = blockpool_unmap, .socket = socket, + .socketpair = socketPair, .shm_unlink = shm_unlink, .dynlib_get_obj_member = dynlib_get_obj_member, .dynlib_dlsym = dynlib_dlsym, diff --git a/rpcsx-os/orbis-kernel-config/orbis-config.hpp b/rpcsx-os/orbis-kernel-config/orbis-config.hpp index 9f44e951b..206999c8a 100644 --- a/rpcsx-os/orbis-kernel-config/orbis-config.hpp +++ b/rpcsx-os/orbis-kernel-config/orbis-config.hpp @@ -43,19 +43,23 @@ using caddr_t = ptr; [[nodiscard]] inline ErrorCode ureadRaw(void *kernelAddress, ptr userAddress, size_t size) { - auto addr = reinterpret_cast(userAddress); - if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) - return ErrorCode::FAULT; - std::memcpy(kernelAddress, userAddress, size); + if (size != 0) { + auto addr = reinterpret_cast(userAddress); + if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) + return ErrorCode::FAULT; + std::memcpy(kernelAddress, userAddress, size); + } return {}; } [[nodiscard]] inline ErrorCode uwriteRaw(ptr userAddress, const void *kernelAddress, size_t size) { - auto addr = reinterpret_cast(userAddress); - if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) - return ErrorCode::FAULT; - std::memcpy(userAddress, kernelAddress, size); + if (size != 0) { + auto addr = reinterpret_cast(userAddress); + if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) + return ErrorCode::FAULT; + std::memcpy(userAddress, kernelAddress, size); + } return {}; } @@ -73,7 +77,8 @@ uwriteRaw(ptr userAddress, const void *kernelAddress, size_t size) { return {}; } -template [[nodiscard]] ErrorCode uread(T &result, ptr pointer) { +template +[[nodiscard]] ErrorCode uread(T &result, ptr pointer) { return ureadRaw(&result, pointer, sizeof(T)); } @@ -90,14 +95,15 @@ template } template -[[nodiscard]] ErrorCode uread(T *result, ptr pointer, std::size_t count) { +[[nodiscard]] ErrorCode uread(T *result, ptr pointer, + std::size_t count) { return ureadRaw(&result, pointer, sizeof(T) * count); } template [[nodiscard]] ErrorCode uwrite(ptr pointer, const T *data, std::size_t count) { - return uwriteRaw(pointer, &data, sizeof(T) * count); + return uwriteRaw(pointer, data, sizeof(T) * count); } inline uint64_t readRegister(void *context, RegisterId id) { diff --git a/rpcsx-os/vfs.cpp b/rpcsx-os/vfs.cpp index dc5baeecc..502497f50 100644 --- a/rpcsx-os/vfs.cpp +++ b/rpcsx-os/vfs.cpp @@ -84,8 +84,8 @@ void rx::vfs::addDevice(std::string name, IoDevice *device) { gDevFs->devices[std::move(name)] = device; } -static std::pair, std::string> -get(const std::filesystem::path &guestPath) { +std::pair, std::string> +rx::vfs::get(const std::filesystem::path &guestPath) { std::string normalPath = std::filesystem::path(guestPath).lexically_normal(); std::string_view path = normalPath; orbis::Ref device; @@ -95,11 +95,18 @@ get(const std::filesystem::path &guestPath) { for (auto &mount : gMountsMap) { if (!path.starts_with(mount.first)) { - continue; + if (mount.first.size() - 1 != path.size() || + !std::string_view(mount.first).starts_with(path)) { + continue; + } } device = mount.second; - path.remove_prefix(mount.first.length()); + if (path.size() > mount.first.length()) { + path.remove_prefix(mount.first.length()); + } else { + path = {}; + } return {mount.second, std::string(path)}; } @@ -131,6 +138,7 @@ orbis::SysResult rx::vfs::open(std::string_view path, int flags, int mode, if (device == nullptr) { return orbis::ErrorCode::NOENT; } + // std::fprintf(stderr, "sys_open %s\n", std::string(path).c_str()); return device->open(file, devPath.c_str(), flags, mode, thread); } diff --git a/rpcsx-os/vfs.hpp b/rpcsx-os/vfs.hpp index 873a51137..2edb29e2d 100644 --- a/rpcsx-os/vfs.hpp +++ b/rpcsx-os/vfs.hpp @@ -12,6 +12,8 @@ void fork(); void initialize(); void deinitialize(); void addDevice(std::string name, IoDevice *device); +std::pair, std::string> +get(const std::filesystem::path &guestPath); orbis::SysResult mount(const std::filesystem::path &guestPath, IoDevice *dev); orbis::SysResult open(std::string_view path, int flags, int mode, orbis::Ref *file, orbis::Thread *thread); diff --git a/rpcsx-os/vm.cpp b/rpcsx-os/vm.cpp index 2c908b265..0b8308526 100644 --- a/rpcsx-os/vm.cpp +++ b/rpcsx-os/vm.cpp @@ -304,8 +304,8 @@ struct Block { Group groups[kGroupsInBlock]; void setFlags(std::uint64_t firstPage, std::uint64_t pagesCount, - std::uint32_t flags) { - modifyFlags(firstPage, pagesCount, flags, ~static_cast(0)); + std::uint32_t flags, bool noOverwrite) { + modifyFlags(firstPage, pagesCount, flags, ~static_cast(0), noOverwrite); } void addFlags(std::uint64_t firstPage, std::uint64_t pagesCount, @@ -342,7 +342,8 @@ struct Block { } void modifyFlags(std::uint64_t firstPage, std::uint64_t pagesCount, - std::uint32_t addFlags, std::uint32_t removeFlags) { + std::uint32_t addFlags, std::uint32_t removeFlags, + bool noOverwrite = false) { std::uint64_t groupIndex = firstPage / kGroupSize; std::uint64_t addAllocatedFlags = @@ -387,6 +388,10 @@ struct Block { auto &group = groups[groupIndex++]; + if (noOverwrite) { + mask &= ~group.allocated; + } + group.allocated = (group.allocated & ~(removeAllocatedFlags & mask)) | (addAllocatedFlags & mask); group.shared = (group.shared & ~(removeSharedFlags & mask)) | @@ -405,30 +410,61 @@ struct Block { (addGpuWritableFlags & mask); } - while (pagesCount >= kGroupSize) { - pagesCount -= kGroupSize; + if (noOverwrite) { + while (pagesCount >= kGroupSize) { + pagesCount -= kGroupSize; - auto &group = groups[groupIndex++]; + auto &group = groups[groupIndex++]; + auto mask = ~group.allocated; - group.allocated = - (group.allocated & ~removeAllocatedFlags) | addAllocatedFlags; - group.shared = (group.shared & ~removeSharedFlags) | addSharedFlags; - group.readable = - (group.readable & ~removeReadableFlags) | addReadableFlags; - group.writable = - (group.writable & ~removeWritableFlags) | addWritableFlags; - group.executable = - (group.executable & ~removeExecutableFlags) | addExecutableFlags; - group.gpuReadable = - (group.gpuReadable & ~removeGpuReadableFlags) | addGpuReadableFlags; - group.gpuWritable = - (group.gpuWritable & ~removeGpuWritableFlags) | addGpuWritableFlags; + group.allocated = (group.allocated & ~(removeAllocatedFlags & mask)) | + (addAllocatedFlags & mask); + group.shared = (group.shared & ~(removeSharedFlags & mask)) | + (addSharedFlags & mask); + group.readable = (group.readable & ~(removeReadableFlags & mask)) | + (addReadableFlags & mask); + group.writable = (group.writable & ~(removeWritableFlags & mask)) | + (addWritableFlags & mask); + group.executable = + (group.executable & ~(removeExecutableFlags & mask)) | + (addExecutableFlags & mask); + group.gpuReadable = + (group.gpuReadable & ~(removeGpuReadableFlags & mask)) | + (addGpuReadableFlags & mask); + group.gpuWritable = + (group.gpuWritable & ~(removeGpuWritableFlags & mask)) | + (addGpuWritableFlags & mask); + } + } else { + while (pagesCount >= kGroupSize) { + pagesCount -= kGroupSize; + + auto &group = groups[groupIndex++]; + + group.allocated = + (group.allocated & ~removeAllocatedFlags) | addAllocatedFlags; + group.shared = (group.shared & ~removeSharedFlags) | addSharedFlags; + group.readable = + (group.readable & ~removeReadableFlags) | addReadableFlags; + group.writable = + (group.writable & ~removeWritableFlags) | addWritableFlags; + group.executable = + (group.executable & ~removeExecutableFlags) | addExecutableFlags; + group.gpuReadable = + (group.gpuReadable & ~removeGpuReadableFlags) | addGpuReadableFlags; + group.gpuWritable = + (group.gpuWritable & ~removeGpuWritableFlags) | addGpuWritableFlags; + } } if (pagesCount > 0) { auto mask = makePagesMask(0, pagesCount); auto &group = groups[groupIndex++]; + if (noOverwrite) { + mask &= ~group.allocated; + } + group.allocated = (group.allocated & ~(removeAllocatedFlags & mask)) | (addAllocatedFlags & mask); group.shared = (group.shared & ~(removeSharedFlags & mask)) | @@ -645,7 +681,7 @@ static void reserve(std::uint64_t startAddress, std::uint64_t endAddress) { auto pagesCount = (endAddress - startAddress + (rx::vm::kPageSize - 1)) >> rx::vm::kPageShift; - gBlocks[blockIndex - kFirstBlock].setFlags(firstPage, pagesCount, kAllocated); + gBlocks[blockIndex - kFirstBlock].setFlags(firstPage, pagesCount, kAllocated, false); } void rx::vm::fork(std::uint64_t pid) { @@ -784,6 +820,12 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, flags &= ~kMapFlagsAlignMask; + bool noOverwrite = addr != 0 && (flags & kMapFlagNoOverwrite) == kMapFlagNoOverwrite; + if (noOverwrite) { + flags |= kMapFlagFixed; + } + flags &= ~kMapFlagNoOverwrite; + if (hitAddress & (alignment - 1)) { if (flags & kMapFlagStack) { hitAddress = utils::alignDown(hitAddress - 1, alignment); @@ -844,18 +886,17 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, } if (address == 0) { - // for (auto blockIndex = kFirstUserBlock; blockIndex <= kLastUserBlock; - // ++blockIndex) { - std::size_t blockIndex = 0; // system managed block + for (auto blockIndex = kFirstBlock; blockIndex <= 2; ++blockIndex) { + // std::size_t blockIndex = 0; // system managed block - auto pageAddress = - gBlocks[blockIndex - kFirstBlock].findFreePages(pagesCount, alignment); + auto pageAddress = gBlocks[blockIndex - kFirstBlock].findFreePages( + pagesCount, alignment); - if (pageAddress != kBadAddress) { - address = (pageAddress << kPageShift) | (blockIndex * kBlockSize); - // break; + if (pageAddress != kBadAddress) { + address = (pageAddress << kPageShift) | (blockIndex * kBlockSize); + break; + } } - // } } if (address == 0) { @@ -881,9 +922,19 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, bool isShared = (flags & kMapFlagShared) == kMapFlagShared; flags &= ~(kMapFlagFixed | kMapFlagAnonymous | kMapFlagShared); - gBlocks[(address >> kBlockShift) - kFirstBlock].setFlags( - (address & kBlockMask) >> kPageShift, pagesCount, - (prot & (kMapProtCpuAll | kMapProtGpuAll)) | kAllocated | (isShared ? kShared : 0)); + auto &block = gBlocks[(address >> kBlockShift) - kFirstBlock]; + if (noOverwrite) { + auto firstPage = (address & kBlockMask) >> kPageShift; + for (std::size_t i = 0; i < pagesCount; ++i) { + if (block.getProtection(firstPage + i)) { + return (void *)-1; + } + } + } + + block.setFlags((address & kBlockMask) >> kPageShift, pagesCount, + (prot & (kMapProtCpuAll | kMapProtGpuAll)) | kAllocated | + (isShared ? kShared : 0), false); /* if (flags & kMapFlagStack) { @@ -933,7 +984,9 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, if (auto thr = orbis::g_currentThread) { std::fprintf(stderr, "sending mapping %lx-%lx, pid %lx\n", address, address + len, thr->tproc->pid); - rx::bridge.sendMemoryProtect(thr->tproc->pid, address, len, prot); + if (!noOverwrite) { + rx::bridge.sendMemoryProtect(thr->tproc->pid, address, len, prot); + } } else { std::fprintf(stderr, "ignoring mapping %lx-%lx\n", address, address + len); } @@ -1001,7 +1054,7 @@ bool rx::vm::protect(void *addr, std::uint64_t size, std::int32_t prot) { gBlocks[(address >> kBlockShift) - kFirstBlock].setFlags( (address & kBlockMask) >> kPageShift, pages, - kAllocated | (prot & (kMapProtCpuAll | kMapProtGpuAll))); + kAllocated | (prot & (kMapProtCpuAll | kMapProtGpuAll)), false); if (auto thr = orbis::g_currentThread) { rx::bridge.sendMemoryProtect( @@ -1014,7 +1067,8 @@ bool rx::vm::protect(void *addr, std::uint64_t size, std::int32_t prot) { static std::int32_t getPageProtectionImpl(std::uint64_t address) { return gBlocks[(address >> kBlockShift) - kFirstBlock].getProtection( - (address & kBlockMask) >> rx::vm::kPageShift) & ~kShared; + (address & kBlockMask) >> rx::vm::kPageShift) & + ~kShared; } bool rx::vm::queryProtection(const void *addr, std::uint64_t *startAddress,