merge rpcsx-gpu and rpcsx-os

initial watchdog implementation
implement gpu -> os events
implement main gfx queue
This commit is contained in:
DH 2024-10-12 05:24:58 +03:00
parent 8e9711e0f6
commit 0c16e294d4
236 changed files with 4649 additions and 4669 deletions

View file

@ -2,6 +2,7 @@
#include "KernelAllocator.hpp"
#include "evf.hpp"
#include "ipmi.hpp"
#include "orbis/note.hpp"
#include "osem.hpp"
#include "thread/types.hpp"
#include "utils/IdMap.hpp"
@ -174,9 +175,12 @@ public:
return getUmtxChainIndexed(1, t, flags, ptr);
}
Ref<EventEmitter> deviceEventEmitter;
Ref<RcBase> shmDevice;
Ref<RcBase> dmemDevice;
Ref<RcBase> blockpoolDevice;
shared_mutex gpuDeviceMtx;
Ref<RcBase> gpuDevice;
uint sdkVersion{};
uint fwSdkVersion{};
uint safeMode{};

View file

@ -1,4 +1,5 @@
#pragma once
#include <compare>
namespace orbis {
enum class ErrorCode : int;
@ -18,5 +19,13 @@ public:
[[nodiscard]] int value() const { return mValue < 0 ? -mValue : mValue; }
[[nodiscard]] bool isError() const { return mValue < 0; }
[[nodiscard]] auto operator<=>(ErrorCode ec) const {
return static_cast<ErrorCode>(value()) <=> ec;
}
[[nodiscard]] auto operator<=>(SysResult other) const {
return value() <=> other.value();
}
};
} // namespace orbis

View file

@ -2,8 +2,8 @@
#include "KernelAllocator.hpp"
#include "orbis-config.hpp"
#include "orbis/utils/Rc.hpp"
#include "utils/SharedMutex.hpp"
#include <mutex>
#include <set>
namespace orbis {
@ -71,6 +71,7 @@ struct KEvent {
ptr<void> udata;
};
struct EventEmitter;
struct KQueue;
struct KNote {
shared_mutex mutex;
@ -80,6 +81,7 @@ struct KNote {
bool enabled = true;
bool triggered = false;
void *linked = nullptr; // TODO: use Ref<>
kvector<Ref<EventEmitter>> emitters;
~KNote();
};
@ -88,6 +90,8 @@ struct EventEmitter : orbis::RcBase {
shared_mutex mutex;
std::set<KNote *, std::less<>, kallocator<KNote *>> notes;
void emit(uint filter, uint fflags = 0, intptr_t data = 0);
void emit(sshort filter, uint fflags = 0, intptr_t data = 0);
void subscribe(KNote *note);
void unsubscribe(KNote *note);
};
} // namespace orbis

View file

@ -46,6 +46,7 @@ struct NamedMemoryRange {
struct Process final {
KernelContext *context = nullptr;
pid_t pid = -1;
int gfxRing = 0;
std::uint64_t hostPid = -1;
sysentvec *sysent = nullptr;
ProcessState state = ProcessState::NEW;

View file

@ -3,7 +3,7 @@
namespace orbis {
using lwpid_t = int32_t;
using pid_t = int64_t;
using pid_t = int32_t;
using uid_t = uint32_t;
using gid_t = uint32_t;

View file

@ -49,11 +49,11 @@ template <typename T> class Ref {
public:
Ref() = default;
Ref(std::nullptr_t) {}
Ref(std::nullptr_t) noexcept {}
template <typename OT>
requires(std::is_base_of_v<T, OT>)
Ref(OT *ref) : m_ref(ref) {
Ref(OT *ref) noexcept : m_ref(ref) {
if (m_ref != nullptr) {
ref->incRef();
}
@ -61,7 +61,7 @@ public:
template <typename OT>
requires(std::is_base_of_v<T, OT>)
Ref(const Ref<OT> &other) : m_ref(other.get()) {
Ref(const Ref<OT> &other) noexcept : m_ref(other.get()) {
if (m_ref != nullptr) {
m_ref->incRef();
}
@ -69,42 +69,42 @@ public:
template <typename OT>
requires(std::is_base_of_v<T, OT>)
Ref(Ref<OT> &&other) : m_ref(other.release()) {}
Ref(Ref<OT> &&other) noexcept : m_ref(other.release()) {}
Ref(const Ref &other) : m_ref(other.get()) {
Ref(const Ref &other) noexcept : m_ref(other.get()) {
if (m_ref != nullptr) {
m_ref->incRef();
}
}
Ref(Ref &&other) : m_ref(other.release()) {}
Ref(Ref &&other) noexcept : m_ref(other.release()) {}
template <typename OT>
requires(std::is_base_of_v<T, OT>)
Ref &operator=(Ref<OT> &&other) {
Ref &operator=(Ref<OT> &&other) noexcept {
other.template cast<T>().swap(*this);
return *this;
}
template <typename OT>
requires(std::is_base_of_v<T, OT>)
Ref &operator=(OT *other) {
Ref &operator=(OT *other) noexcept {
*this = Ref(other);
return *this;
}
template <typename OT>
requires(std::is_base_of_v<T, OT>)
Ref &operator=(const Ref<OT> &other) {
Ref &operator=(const Ref<OT> &other) noexcept {
*this = Ref(other);
return *this;
}
Ref &operator=(const Ref &other) {
Ref &operator=(const Ref &other) noexcept {
*this = Ref(other);
return *this;
}
Ref &operator=(Ref &&other) {
Ref &operator=(Ref &&other) noexcept {
other.swap(*this);
return *this;
}
@ -115,7 +115,7 @@ public:
}
}
void swap(Ref<T> &other) { std::swap(m_ref, other.m_ref); }
void swap(Ref<T> &other) noexcept { std::swap(m_ref, other.m_ref); }
T *get() const { return m_ref; }
T *release() { return std::exchange(m_ref, nullptr); }
T *operator->() const { return m_ref; }
@ -126,10 +126,17 @@ public:
auto operator<=>(const Ref &other) const = default;
template <typename OtherT> Ref<OtherT> cast() {
return Ref<OtherT>(dynamic_cast<OtherT *>(m_ref));
return dynamic_cast<OtherT *>(m_ref);
}
template <typename OtherT> Ref<OtherT> staticCast() {
return Ref<OtherT>(static_cast<OtherT *>(m_ref));
return static_cast<OtherT *>(m_ref);
}
template <typename OtherT> OtherT *rawCast() {
return dynamic_cast<OtherT *>(m_ref);
}
template <typename OtherT> OtherT *rawStaticCast() {
return static_cast<OtherT *>(m_ref);
}
};

View file

@ -9,6 +9,8 @@
#include <unistd.h>
static const std::uint64_t g_allocProtWord = 0xDEADBEAFBADCAFE1;
static constexpr auto kHeapBaseAddress = 0x600'0000'0000;
static constexpr auto kHeapSize = 0x2'0000'0000;
namespace orbis {
thread_local Thread *g_currentThread;
@ -16,7 +18,7 @@ thread_local Thread *g_currentThread;
KernelContext &g_context = *[]() -> KernelContext * {
// Allocate global shared kernel memory
// TODO: randomize for hardening and reduce size
auto ptr = mmap(reinterpret_cast<void *>(0x200'0000'0000), 0x2'0000'0000,
auto ptr = mmap(reinterpret_cast<void *>(kHeapBaseAddress), kHeapSize,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (ptr == MAP_FAILED)
@ -166,15 +168,32 @@ void *KernelContext::kalloc(std::size_t size, std::size_t align) {
align = std::max<std::size_t>(align, __STDCPP_DEFAULT_NEW_ALIGNMENT__);
auto heap = reinterpret_cast<std::uintptr_t>(m_heap_next);
heap = (heap + (align - 1)) & ~(align - 1);
if (heap + size > kHeapBaseAddress + kHeapSize) {
std::fprintf(stderr, "out of kernel memory");
std::abort();
}
// Check overflow
if (heap + size < heap) {
std::fprintf(stderr, "too big allocation");
std::abort();
}
auto result = reinterpret_cast<void *>(heap);
std::memcpy(std::bit_cast<std::byte *>(result) + size, &g_allocProtWord,
sizeof(g_allocProtWord));
m_heap_next = reinterpret_cast<void *>(heap + size + sizeof(g_allocProtWord));
// Check overflow
if (heap + size < heap)
std::abort();
if (heap + size > (uintptr_t)&g_context + 0x1'0000'0000)
std::abort();
if (true) {
heap = reinterpret_cast<std::uintptr_t>(m_heap_next);
align = std::min<std::size_t>(align, 4096);
heap = (heap + (align - 1)) & ~(align - 1);
size = 4096;
::mmap(reinterpret_cast<void *>(heap), size, PROT_NONE, MAP_FIXED, -1, 0);
m_heap_next = reinterpret_cast<void *>(heap + size);
}
return result;
}

View file

@ -1,7 +1,13 @@
#include "event.hpp"
#include "thread/Process.hpp"
#include <algorithm>
orbis::KNote::~KNote() {
while (!emitters.empty()) {
emitters.back()->unsubscribe(this);
}
if (linked == nullptr) {
return;
}
@ -14,7 +20,7 @@ orbis::KNote::~KNote() {
}
}
void orbis::EventEmitter::emit(uint filter, uint fflags, intptr_t data) {
void orbis::EventEmitter::emit(sshort filter, uint fflags, intptr_t data) {
std::lock_guard lock(mutex);
for (auto note : notes) {
@ -40,3 +46,28 @@ void orbis::EventEmitter::emit(uint filter, uint fflags, intptr_t data) {
note->queue->cv.notify_all(note->queue->mtx);
}
}
void orbis::EventEmitter::subscribe(KNote *note) {
std::lock_guard lock(mutex);
notes.insert(note);
note->emitters.emplace_back(this);
}
void orbis::EventEmitter::unsubscribe(KNote *note) {
std::lock_guard lock(mutex);
notes.erase(note);
auto it = std::ranges::find(note->emitters, this);
if (it == note->emitters.end()) {
return;
}
std::size_t index = it - note->emitters.begin();
auto lastEmitter = note->emitters.size() - 1;
if (index != lastEmitter) {
std::swap(note->emitters[index], note->emitters[lastEmitter]);
}
note->emitters.pop_back();
}

View file

@ -223,6 +223,10 @@ orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread,
ptr<uint> unk;
};
if (paramsSz != sizeof(IpmiServerReceivePacketParams)) {
return orbis::ErrorCode::INVAL;
}
IpmiServerReceivePacketParams _params;
ORBIS_RET_ON_ERROR(
@ -265,9 +269,6 @@ orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread,
auto asyncMessage = (IpmiAsyncMessageHeader *)_packet.message.data();
ORBIS_LOG_ERROR(__FUNCTION__, server->name, asyncMessage->methodId,
asyncMessage->numInData, asyncMessage->pid);
ORBIS_LOG_ERROR(__FUNCTION__, server->name,
*(std::uint64_t *)(*(long *)server->eventHandler + 0x18));
}
if (_params.bufferSize < _packet.message.size()) {
@ -380,11 +381,13 @@ orbis::SysResult orbis::sysIpmiSessionRespondSync(Thread *thread,
clientTid = session->server->tidToClientTid.at(thread->tid);
}
ORBIS_LOG_ERROR(__FUNCTION__, session->client->name, _params.errorCode);
if (_params.errorCode != 0) {
ORBIS_LOG_ERROR(__FUNCTION__, session->client->name, _params.errorCode);
thread->where();
// HACK: completely broken audio audio support should not be visible
// HACK: completely broken audio support should not be visible
if (session->client->name == "SceSysAudioSystemIpc" &&
_params.errorCode == -1) {
_params.errorCode = 0;
@ -1268,6 +1271,10 @@ orbis::SysResult orbis::sysIpmiClientWaitEventFlag(Thread *thread,
static_assert(sizeof(IpmiWaitEventFlagParam) == 0x28);
if (paramsSz != sizeof(IpmiWaitEventFlagParam)) {
return ErrorCode::INVAL;
}
IpmiWaitEventFlagParam _params;
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiWaitEventFlagParam>(params)));

View file

@ -113,17 +113,15 @@ static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) {
nodeIt->file = fd;
if (auto eventEmitter = fd->event) {
std::unique_lock lock(eventEmitter->mutex);
// if (change.filter == kEvFiltWrite) {
// nodeIt->triggered = true;
// kq->cv.notify_all(kq->mtx);
// }
eventEmitter->subscribe(&*nodeIt);
nodeIt->triggered = true;
eventEmitter->notes.insert(&*nodeIt);
kq->cv.notify_all(kq->mtx);
} else if (note.file->hostFd < 0) {
ORBIS_LOG_ERROR("Unimplemented event emitter", change.ident);
}
} else if (change.filter == kEvFiltGraphicsCore ||
change.filter == kEvFiltDisplay) {
g_context.deviceEventEmitter->subscribe(&*nodeIt);
}
}
}
@ -172,19 +170,14 @@ static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) {
nodeIt->triggered = true;
kq->cv.notify_all(kq->mtx);
}
} else if (change.filter == kEvFiltGraphicsCore) {
} else if (change.filter == kEvFiltDisplay && change.ident >> 48 == 0x6301) {
nodeIt->triggered = true;
if (change.ident == 0x84) {
// clock change event
nodeIt->event.data |= 1000ull << 16; // clock
}
kq->cv.notify_all(kq->mtx);
} else if (change.filter == kEvFiltDisplay) {
if (change.ident != 0x51000100000000 && change.ident != 0x63010100000000) {
nodeIt->triggered = true;
kq->cv.notify_all(kq->mtx);
}
} else if (change.filter == kEvFiltGraphicsCore && change.ident == 0x84) {
nodeIt->triggered = true;
nodeIt->event.data |= 1000ull << 16; // clock
kq->cv.notify_all(kq->mtx);
}
return {};

View file

@ -307,8 +307,8 @@ SysResult kern_sysctl(Thread *thread, ptr<sint> name, uint namelen,
case sysctl_ctl::unspec: {
switch (name[1]) {
case 3: {
std::fprintf(stderr, " unspec - get name of '%s'\n",
std::string((char *)new_, newlen).c_str());
// std::fprintf(stderr, " unspec - get name of '%s'\n",
// std::string((char *)new_, newlen).c_str());
auto searchName = std::string_view((char *)new_, newlen);
auto *dest = (std::uint32_t *)old;
std::uint32_t count = 0;

View file

@ -305,7 +305,7 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr<ucond> cv,
ORBIS_LOG_FATAL("umtx_cv_wait: UNKNOWN wflags", wflags);
return ErrorCode::INVAL;
}
if ((wflags & kCvWaitClockId) != 0 && ut + 1) {
if ((wflags & kCvWaitClockId) != 0 && ut + 1 && cv->clockid != 0) {
ORBIS_LOG_WARNING("umtx_cv_wait: CLOCK_ID", wflags, cv->clockid);
// std::abort();
return ErrorCode::NOSYS;