mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-04 22:19:02 +00:00
merge rpcsx-gpu and rpcsx-os
initial watchdog implementation implement gpu -> os events implement main gfx queue
This commit is contained in:
parent
8e9711e0f6
commit
0c16e294d4
236 changed files with 4649 additions and 4669 deletions
|
|
@ -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{};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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)));
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue