implement unix socket ops

implement cross process dmem support
implement ipmi try send message
implement sys_batch_map
store saves to game directory (.rpcsx subfolder)
fix get dir entries
added uvd & vce devices
This commit is contained in:
DH 2023-12-31 14:30:49 +03:00
parent a6211b514f
commit 6e25f347d3
39 changed files with 1526 additions and 294 deletions

View file

@ -1,10 +1,10 @@
#pragma once
#include <orbis/utils/SharedMutex.hpp>
#include <atomic>
#include <cstdint>
#include <cstring>
#include <initializer_list>
#include <orbis/utils/SharedCV.hpp>
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<std::uint64_t> 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<std::uint64_t> 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();

View file

@ -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 &regs,
std::span<std::uint32_t> &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(

View file

@ -0,0 +1,9 @@
#pragma once
namespace orbis {
struct SocketAddress {
unsigned char len;
unsigned char family;
char data[14];
};
} // namespace orbis

View file

@ -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<struct sf_hdtr> hdtr, ptr<off_t> sbytes, sint flags,
Thread *thread) = nullptr;
};
struct File : RcBase {
@ -49,6 +79,7 @@ struct File : RcBase {
const FileOps *ops = nullptr;
Ref<RcBase> device;
std::uint64_t nextOff = 0;
int hostFd = -1;
utils::kvector<Dirent> dirEntries;
};
} // namespace orbis

View file

@ -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<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiSessionRespondSync(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientGetMessage(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientTryGetMessage(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiSessionTrySendMessage(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysIpmiClientDisconnect(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysIpmiSessionGetClientPid(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientInvokeSyncMethod(Thread *thread, ptr<uint> result,

View file

@ -7,7 +7,7 @@
#include <set>
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<KQueue> queue;
Ref<File> file;
KEvent event{};
bool enabled = true;
bool triggered = false;

View file

@ -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<struct msghdr> msg,
SysResult sys_sendmsg(Thread *thread, sint s, ptr<struct msghdr> msg,
sint flags);
SysResult sys_recvfrom(Thread *thread, sint s, caddr_t buf, size_t len,
sint flags, ptr<struct sockaddr> from,
sint flags, ptr<SocketAddress> from,
ptr<uint32_t> fromlenaddr);
SysResult sys_accept(Thread *thread, sint s, ptr<struct sockaddr> from,
SysResult sys_accept(Thread *thread, sint s, ptr<SocketAddress> from,
ptr<uint32_t> fromlenaddr);
SysResult sys_getpeername(Thread *thread, sint fdes, ptr<struct sockaddr> asa,
SysResult sys_getpeername(Thread *thread, sint fdes, ptr<SocketAddress> asa,
ptr<uint32_t> alen);
SysResult sys_getsockname(Thread *thread, sint fdes, ptr<struct sockaddr> asa,
SysResult sys_getsockname(Thread *thread, sint fdes, ptr<SocketAddress> asa,
ptr<uint32_t> alen);
SysResult sys_access(Thread *thread, ptr<char> path, sint flags);
SysResult sys_chflags(Thread *thread, ptr<char> path, sint flags);
@ -634,7 +635,8 @@ SysResult sys_evf_cancel(Thread *thread, sint id, uint64_t value,
ptr<sint> pNumWaitThreads);
SysResult sys_query_memory_protection(Thread *thread, ptr<void> address,
ptr<MemoryProtection> protection);
SysResult sys_batch_map(Thread *thread /* TODO */);
SysResult sys_batch_map(Thread *thread, sint unk, sint flags, ptr<BatchMapEntry> entries,
sint entriesCount, ptr<sint> processedCount);
SysResult sys_osem_create(Thread *thread, ptr<const char[32]> 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<sint> 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 */);

View file

@ -51,6 +51,8 @@ struct ProcessOps {
SysResult (*blockpool_unmap)(Thread *thread, caddr_t addr, size_t len);
SysResult (*socket)(Thread *thread, ptr<const char> name, sint domain,
sint type, sint protocol, Ref<File> *file);
SysResult (*socketpair)(Thread *thread, sint domain, sint type, sint protocol,
Ref<File> *a, Ref<File> *b);
SysResult (*shm_unlink)(Thread *thread, const char *path);
SysResult (*dynlib_get_obj_member)(Thread *thread, ModuleHandle handle,
uint64_t index, ptr<ptr<void>> addrp);

View file

@ -1,6 +1,9 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <span>
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<const std::byte *>(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<typename T>
std::size_t write(const T &object) {
return write(&object, sizeof(T));
}
};
} // namespace orbis

View file

@ -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 <typename OT>
requires(std::is_base_of_v<T, OT>)
Ref &operator=(Ref<OT> &&other) {
other.swap(*this);
other.template cast<T>().swap(*this);
return *this;
}

View file

@ -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<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
auto client = thread->tproc->ipmiMap.get(kid).cast<IpmiClient>();
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<uint>(result, 0x80020000 + static_cast<int>(ErrorCode::AGAIN));
}
orbis::SysResult orbis::sysIpmiClientTryGetMessage(Thread *thread,
ptr<uint> 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<SceIpmiClientTryGetArgs>(params)));
@ -389,6 +408,81 @@ orbis::SysResult orbis::sysIpmiClientTryGetMessage(Thread *thread,
return uwrite<uint>(result, 0);
}
orbis::SysResult orbis::sysIpmiSessionTrySendMessage(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
struct SceIpmiClientTrySendArgs {
uint32_t unk; // 0
uint32_t padding;
ptr<std::byte> message;
uint64_t size;
};
static_assert(sizeof(SceIpmiClientTrySendArgs) == 0x18);
if (paramsSz != sizeof(SceIpmiClientTrySendArgs)) {
return ErrorCode::INVAL;
}
auto session = thread->tproc->ipmiMap.get(kid).cast<IpmiSession>();
if (session == nullptr) {
return ErrorCode::INVAL;
}
SceIpmiClientTrySendArgs _params;
ORBIS_RET_ON_ERROR(uread(_params, ptr<SceIpmiClientTrySendArgs>(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<uint>(result, 0);
}
orbis::SysResult orbis::sysIpmiClientDisconnect(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
struct SceIpmiClientDisconnectArgs {
ptr<sint> status;
};
if (paramsSz != sizeof(SceIpmiClientDisconnectArgs)) {
return ErrorCode::INVAL;
}
auto client = thread->tproc->ipmiMap.get(kid).cast<IpmiClient>();
if (client == nullptr) {
return ErrorCode::INVAL;
}
SceIpmiClientDisconnectArgs _params;
ORBIS_RET_ON_ERROR(uread(_params, ptr<SceIpmiClientDisconnectArgs>(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<uint>(result, 0);
}
orbis::SysResult orbis::sysIpmiSessionGetClientPid(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
@ -474,7 +568,6 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr<uint> 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<uint> result, uint kid,
ORBIS_LOG_TODO("IPMI: sync call", client->name, _params.method,
thread->tproc->pid);
thread->where();
auto bufLoc = std::bit_cast<char *>(msg + 1);
for (auto &data : std::span(_params.pInData, _params.numInData)) {
@ -539,6 +630,10 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr<uint> 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,

View file

@ -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 <span>
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<orbis::Pipe *>(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<std::size_t>(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<orbis::Pipe *>(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::Pipe> orbis::createPipe() {
auto result = knew<Pipe>();

View file

@ -7,6 +7,7 @@
#include <chrono>
#include <list>
#include <span>
#include <sys/select.h>
orbis::SysResult orbis::sys_kqueue(Thread *thread) {
auto queue = knew<KQueue>();
@ -33,6 +34,28 @@ orbis::SysResult orbis::sys_kqueueex(Thread *thread, ptr<char> 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<KEvent> 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 &note = *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<std::chrono::microseconds>(
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);
}
}
}

View file

@ -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<const char[32]> 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<const char[32]> 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<const char[32]> 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<const char[32]> 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<void> address,
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_batch_map(Thread *thread /* TODO */) {
return ErrorCode::NOSYS;
namespace orbis {
struct BatchMapEntry {
ptr<char> 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<BatchMapEntry> entries,
sint entriesCount,
ptr<sint> 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<void>(_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<const char[32]> name, uint attrs,
@ -418,6 +488,7 @@ orbis::SysResult orbis::sys_osem_create(Thread *thread,
sem = insertedSem;
} else {
sem = knew<Semaphore>(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:

View file

@ -1,10 +1,7 @@
#include "pipe.hpp"
#include "sys/sysproto.hpp"
#include "uio.hpp"
#include "utils/Logs.hpp"
#include <chrono>
#include <sys/socket.h>
#include <thread>
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<SocketAddress>(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<struct sockaddr> from,
ptr<SocketAddress> from,
ptr<uint32_t> 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<SocketAddress>(name), namelen, thread);
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_socketpair(Thread *thread, sint domain, sint type,
sint protocol, ptr<sint> 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<File> a;
Ref<File> 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<struct sockaddr> from,
ptr<SocketAddress> from,
ptr<uint32_t> fromlenaddr) {
auto pipe = thread->tproc->fileDescriptors.get(s).cast<Pipe>();
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<struct msghdr> 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<sint> 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<struct sockaddr> asa,
ptr<SocketAddress> asa,
ptr<uint32_t> alen) {
return ErrorCode::NOSYS;
// return uwrite<uint32_t>(alen, sizeof(SockAddr));
ORBIS_LOG_TODO(__FUNCTION__);
return {};
}
orbis::SysResult orbis::sys_getpeername(Thread *thread, sint fdes,
ptr<struct sockaddr> asa,
ptr<SocketAddress> asa,
ptr<uint32_t> alen) {
return ErrorCode::NOSYS;
}

View file

@ -2,19 +2,52 @@
#include "sys/sysproto.hpp"
#include "utils/Logs.hpp"
#include <filesystem>
#include <span>
orbis::SysResult orbis::sys_sync(Thread *thread) { return ErrorCode::NOSYS; }
orbis::SysResult orbis::sys_quotactl(Thread *thread, ptr<char> 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<char> path,
ptr<struct statfs> 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<struct statfs> 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<struct statfs> 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<char> path, sint mode) {
return ErrorCode::NOSYS;
return {};
}
orbis::SysResult orbis::sys_fchmodat(Thread *thread, sint fd, ptr<char> path,
mode_t mode, sint flag) {
@ -353,7 +386,7 @@ orbis::SysResult orbis::sys_getdirentries(Thread *thread, sint fd,
auto next = std::min<uint64_t>(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<orbis::Dirent>(buf), entries + pos, next - pos);
if (result.isError())
return result;

View file

@ -23,7 +23,7 @@
#include <GLFW/glfw3.h> // 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);
}

View file

@ -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

View file

@ -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 <cerrno>
#include <dirent.h>
#include <fcntl.h>
#include <filesystem>
#include <netinet/in.h>
#include <span>
#include <string>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <thread>
#include <unistd.h>
#include <unordered_map>
#include <vector>
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<int, orbis::kvector<std::byte>> 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<orbis::File> *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<HostFile *>(file);
if (!hostFile->dirEntries.empty())
return orbis::ErrorCode::ISDIR;
static orbis::ErrorCode host_fd_read(int hostFd, orbis::Uio *uio) {
std::vector<iovec> vec;
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
vec.push_back({.iov_base = entry.base, .iov_len = entry.len});
}
ssize_t cnt = 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<HostFile *>(file);
if (!hostFile->dirEntries.empty())
return orbis::ErrorCode::ISDIR;
std::vector<iovec> vec;
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
vec.push_back({.iov_base = entry.base, .iov_len = entry.len});
}
ssize_t cnt =
::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<iovec> vec;
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
vec.push_back({.iov_base = entry.base, .iov_len = entry.len});
}
ssize_t cnt = ::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<HostFile *>(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<HostFile *>(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<HostFile *>(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<SocketFile *>(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<SocketFile *>(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<SocketFile *>(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<HostFsDevice>()) {
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<SocketFile *>(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<SocketFile *>(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<sockaddr *>(&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<SocketFile *>(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<HostFsDevice>()) {
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<SocketFile *>(file);
orbis::kvector<std::byte> 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<SocketFile *>(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<SocketFile *>(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<HostFsDevice>(std::move(hostPath));
return orbis::knew<HostFsDevice>(std::move(hostPath), std::move(virtualPath));
}
orbis::Ref<orbis::File> wrapSocket(int hostFd, orbis::kstring name, int dom,
int type, int prot) {
auto s = orbis::knew<SocketFile>();
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<orbis::File> *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<SocketFile>();
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<orbis::File> *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<orbis::Dirent> 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<dirent64 *>(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<IoDevice> device) {
orbis::File *createHostFile(int hostFd, orbis::Ref<IoDevice> device, bool alignTruncate) {
auto newFile = orbis::knew<HostFile>();
newFile->hostFd = hostFd;
newFile->ops = &hostOps;
newFile->device = device;
newFile->alignTruncate = alignTruncate;
return newFile;
}

View file

@ -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<orbis::File> *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<orbis::File> wrapSocket(int hostFd, orbis::kstring name, int dom, int type, int prot);
orbis::ErrorCode createSocket(orbis::Ref<orbis::File> *file,
orbis::kstring name, int dom, int type, int prot);
orbis::File *createHostFile(int hostFd, orbis::Ref<IoDevice> device);
orbis::File *createHostFile(int hostFd, orbis::Ref<IoDevice> device, bool alignTruncate = false);
IoDevice *createFdWrapDevice(int fd);

View file

@ -40,3 +40,5 @@ IoDevice *createGbaseCharacterDevice();
IoDevice *createDevStatCharacterDevice();
IoDevice *createDevCtlCharacterDevice();
IoDevice *createDevActCharacterDevice();
IoDevice *createUVDCharacterDevice();
IoDevice *createVCECharacterDevice();

View file

@ -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 <bits/types/struct_iovec.h>
#include <chrono>
#include <thread>
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<orbis::File> *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<AoutFile>();
newFile->ops = &fileOps;
newFile->device = this;
thread->where();
*file = newFile;
return {};

View file

@ -49,9 +49,10 @@ static orbis::ErrorCode console_write(orbis::File *file, orbis::Uio *uio,
auto dev = dynamic_cast<ConsoleDevice *>(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 {};
}

View file

@ -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();
}

View file

@ -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 <fcntl.h>
#include <mutex>
#include <sys/mman.h>
#include <unistd.h>
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<std::uint64_t>(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<AllocateDirectMemoryArgs *>(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<DmemDevice>();
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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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 {};
}

View file

@ -1,6 +1,7 @@
#include "io-device.hpp"
#include "orbis/KernelAllocator.hpp"
#include "orbis/uio.hpp"
#include <span>
struct NullDevice : public IoDevice {
orbis::ErrorCode open(orbis::Ref<orbis::File> *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 {};
}

View file

@ -38,7 +38,6 @@ orbis::ErrorCode ShmDevice::open(orbis::Ref<orbis::File> *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<orbis::File> *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 {};
}

32
rpcsx-os/iodev/uvd.cpp Normal file
View file

@ -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<orbis::File> *file, const char *path,
std::uint32_t flags, std::uint32_t mode,
orbis::Thread *thread) override {
auto newFile = orbis::knew<UVDFile>();
newFile->ops = &fileOps;
newFile->device = this;
*file = newFile;
return {};
}
};
IoDevice *createUVDCharacterDevice() { return orbis::knew<UVDDevice>(); }

45
rpcsx-os/iodev/vce.cpp Normal file
View file

@ -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<std::uint32_t *>(argp) = 0x700;
return{};
case 0x80488401:
auto unkAddress = *reinterpret_cast<std::uint64_t *>(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<orbis::File> *file, const char *path,
std::uint32_t flags, std::uint32_t mode,
orbis::Thread *thread) override {
auto newFile = orbis::knew<VCEFile>();
newFile->ops = &fileOps;
newFile->device = this;
*file = newFile;
return {};
}
};
IoDevice *createVCECharacterDevice() { return orbis::knew<VCEDevice>(); }

View file

@ -10,6 +10,7 @@
#include <bit>
#include <crypto/sha1.h>
#include <elf.h>
#include <filesystem>
#include <fstream>
#include <map>
#include <orbis/thread/Process.hpp>
@ -968,7 +969,7 @@ Ref<orbis::Module> 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());
}

View file

@ -9,6 +9,7 @@
#include "thread.hpp"
#include "vfs.hpp"
#include "vm.hpp"
#include "xbyak/xbyak.h"
#include <rx/Version.hpp>
#include <elf.h>
@ -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<std::byte *>(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<std::int32_t()> handler) {
syncHandlers[methodId] =
[=](std::int32_t &errorCode, std::vector<std::span<std::byte>> &outData,
const std::vector<std::span<std::byte>> &inData)
-> orbis::ErrorCode {
if (!outData.empty()) {
return orbis::ErrorCode::INVAL;
}
errorCode = handler();
return {};
};
return *this;
}
IpmiServer &createSyncHandler(
std::uint32_t methodId,
std::function<std::int32_t(void *out, std::uint64_t &outSize)> handler) {
@ -693,7 +731,7 @@ struct IpmiServer {
[=](std::int32_t &errorCode, std::vector<std::span<std::byte>> &outData,
const std::vector<std::span<std::byte>> &inData)
-> orbis::ErrorCode {
if (outData.size() != 1) {
if (outData.size() < 1) {
return orbis::ErrorCode::INVAL;
}
@ -732,6 +770,34 @@ struct IpmiServer {
return *this;
}
template <typename OutT, typename InT>
IpmiServer &createSyncHandler(
std::uint32_t methodId,
std::function<std::int32_t(OutT &out, const InT &param)> handler) {
syncHandlers[methodId] =
[=](std::int32_t &errorCode, std::vector<std::span<std::byte>> &outData,
const std::vector<std::span<std::byte>> &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<InT *>(inData[0].data()));
std::memcpy(outData[0].data(), &out, sizeof(out));
outData[0] = outData[0].subspan(0, sizeof(OutT));
return {};
};
return *this;
}
template <typename T>
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<std::byte>(
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<int>(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<std::uint32_t>(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<int>(orbis::ErrorCode::INVAL);
}
size = 1;
*reinterpret_cast<std::uint8_t *>(out) = 1;
return 0;
})
.createSyncHandler(0xa0002,
[=](void *out, std::uint64_t &size) -> std::int32_t {
if (size < 1) {
return 0x8002'0000 +
static_cast<int>(orbis::ErrorCode::INVAL);
}
size = 1;
*reinterpret_cast<std::uint8_t *>(out) = 1;
return 0;
})
.createSyncHandler<std::uint32_t, std::uint32_t>(
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<HostFsDevice>()) {
std::error_code ec;
auto saveDir = hostFs->hostPath + "/.rpcsx/saves/";
if (!std::filesystem::exists(saveDir)) {
return 0x8002'0000 +
static_cast<int>(orbis::ErrorCode::NOENT);
}
}
}
std::string_view result = "/saves";
if (size < result.size() + 1) {
return 0x8002'0000 + static_cast<int>(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<HostFsDevice>()) {
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),

View file

@ -33,6 +33,7 @@
#include <string>
#include <string_view>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <thread>
#include <unistd.h>
@ -356,6 +357,26 @@ orbis::SysResult socket(orbis::Thread *thread, orbis::ptr<const char> 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<File> *a, Ref<File> *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<IoDevice *>(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,

View file

@ -43,19 +43,23 @@ using caddr_t = ptr<char>;
[[nodiscard]] inline ErrorCode
ureadRaw(void *kernelAddress, ptr<const void> userAddress, size_t size) {
auto addr = reinterpret_cast<std::uintptr_t>(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<std::uintptr_t>(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<void> userAddress, const void *kernelAddress, size_t size) {
auto addr = reinterpret_cast<std::uintptr_t>(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<std::uintptr_t>(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<void> userAddress, const void *kernelAddress, size_t size) {
return {};
}
template <typename T> [[nodiscard]] ErrorCode uread(T &result, ptr<const T> pointer) {
template <typename T>
[[nodiscard]] ErrorCode uread(T &result, ptr<const T> pointer) {
return ureadRaw(&result, pointer, sizeof(T));
}
@ -90,14 +95,15 @@ template <typename T, typename U>
}
template <typename T>
[[nodiscard]] ErrorCode uread(T *result, ptr<const T> pointer, std::size_t count) {
[[nodiscard]] ErrorCode uread(T *result, ptr<const T> pointer,
std::size_t count) {
return ureadRaw(&result, pointer, sizeof(T) * count);
}
template <typename T>
[[nodiscard]] ErrorCode uwrite(ptr<T> 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) {

View file

@ -84,8 +84,8 @@ void rx::vfs::addDevice(std::string name, IoDevice *device) {
gDevFs->devices[std::move(name)] = device;
}
static std::pair<orbis::Ref<IoDevice>, std::string>
get(const std::filesystem::path &guestPath) {
std::pair<orbis::Ref<IoDevice>, 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<IoDevice> 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);
}

View file

@ -12,6 +12,8 @@ void fork();
void initialize();
void deinitialize();
void addDevice(std::string name, IoDevice *device);
std::pair<orbis::Ref<IoDevice>, 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<orbis::File> *file, orbis::Thread *thread);

View file

@ -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<std::uint32_t>(0));
std::uint32_t flags, bool noOverwrite) {
modifyFlags(firstPage, pagesCount, flags, ~static_cast<std::uint32_t>(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,