#pragma once #include "AppInfo.hpp" #include "KernelAllocator.hpp" #include "evf.hpp" #include "ipmi.hpp" #include "orbis/note.hpp" #include "osem.hpp" #include "thread/types.hpp" #include "utils/IdMap.hpp" #include "utils/LinkedNode.hpp" #include "utils/SharedCV.hpp" #include "utils/SharedMutex.hpp" #include #include #include #include namespace orbis { struct Process; struct Thread; struct UmtxKey { // TODO: may contain a reference to a shared memory std::uintptr_t addr; orbis::pid_t pid; auto operator<=>(const UmtxKey &) const = default; }; struct UmtxCond { Thread *thr; utils::shared_cv cv; UmtxCond(Thread *thr) : thr(thr) {} }; struct UmtxChain { utils::shared_mutex mtx; using queue_type = utils::kmultimap; queue_type sleep_queue; queue_type spare_queue; std::pair *enqueue(UmtxKey &key, Thread *thr); void erase(std::pair *obj); queue_type::iterator erase(queue_type::iterator it); uint notify_one(const UmtxKey &key); uint notify_all(const UmtxKey &key); uint notify_n(const UmtxKey &key, sint count); }; enum class FwType : std::uint8_t { Unknown, Ps4, Ps5, }; struct RcAppInfo : RcBase, AppInfoEx { orbis::uint32_t appState = 0; }; class alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) KernelContext final { public: KernelContext(); ~KernelContext(); Process *createProcess(pid_t pid); void deleteProcess(Process *proc); Process *findProcessById(pid_t pid) const; Process *findProcessByHostId(std::uint64_t pid) const; utils::LinkedNode *getProcessList() { return m_processes; } long allocatePid() { std::lock_guard lock(m_thread_id_mtx); return m_thread_id_map.emplace(0).first; } long getTscFreq(); void *kalloc(std::size_t size, std::size_t align = __STDCPP_DEFAULT_NEW_ALIGNMENT__); void kfree(void *ptr, std::size_t size); std::pair createEventFlag(utils::kstring name, std::int32_t flags, std::uint64_t initPattern) { std::lock_guard lock(m_evf_mtx); auto [it, inserted] = m_event_flags.try_emplace(std::move(name), nullptr); if (inserted) { it->second = knew(flags, initPattern); std::strncpy(it->second->name, it->first.c_str(), 32); } return {it->second.get(), inserted}; } Ref findEventFlag(std::string_view name) { std::lock_guard lock(m_evf_mtx); if (auto it = m_event_flags.find(name); it != m_event_flags.end()) { return it->second; } return {}; } std::pair createSemaphore(utils::kstring name, std::uint32_t attrs, std::int32_t initCount, std::int32_t maxCount) { std::lock_guard lock(m_sem_mtx); auto [it, inserted] = m_semaphores.try_emplace(std::move(name), nullptr); if (inserted) { it->second = knew(attrs, initCount, maxCount); } return {it->second.get(), inserted}; } Ref findSemaphore(std::string_view name) { std::lock_guard lock(m_sem_mtx); if (auto it = m_semaphores.find(name); it != m_semaphores.end()) { return it->second; } return {}; } std::pair, ErrorCode> createIpmiServer(utils::kstring name) { std::lock_guard lock(m_sem_mtx); auto [it, inserted] = mIpmiServers.try_emplace(std::move(name), nullptr); if (!inserted) { return {it->second, ErrorCode::EXIST}; } it->second = knew(it->first); if (it->second == nullptr) { mIpmiServers.erase(it); return {nullptr, ErrorCode::NOMEM}; } return {it->second, {}}; } Ref findIpmiServer(std::string_view name) { std::lock_guard lock(m_sem_mtx); if (auto it = mIpmiServers.find(name); it != mIpmiServers.end()) { return it->second; } return {}; } std::tuple &, std::unique_lock> getKernelEnv() { std::unique_lock lock(m_kenv_mtx); return {m_kenv, std::move(lock)}; } void setKernelEnv(std::string_view key, std::string_view value) { auto &kenvValue = m_kenv[utils::kstring(key)]; auto len = std::min(sizeof(kenvValue) - 1, value.size()); std::memcpy(kenvValue, value.data(), len); kenvValue[len] = '0'; } enum { c_golden_ratio_prime = 2654404609u, c_umtx_chains = 512, c_umtx_shifts = 23, }; // Use getUmtxChain0 or getUmtxChain1 std::tuple> getUmtxChainIndexed(int i, Thread *t, uint32_t flags, void *ptr); // Internal Umtx: Wait/Cv/Sem auto getUmtxChain0(Thread *t, uint32_t flags, void *ptr) { return getUmtxChainIndexed(0, t, flags, ptr); } // Internal Umtx: Mutex/Umtx/Rwlock auto getUmtxChain1(Thread *t, uint32_t flags, void *ptr) { return getUmtxChainIndexed(1, t, flags, ptr); } Ref deviceEventEmitter; Ref shmDevice; Ref dmemDevice; Ref blockpoolDevice; shared_mutex gpuDeviceMtx; Ref gpuDevice; Ref dceDevice; uint sdkVersion{}; uint fwSdkVersion{}; uint safeMode{}; utils::RcIdMap ipmiMap; RcIdMap appInfos; shared_mutex regMgrMtx; kmap regMgrInt; std::vector> dialogs{}; FwType fwType = FwType::Unknown; bool isDevKit = false; private: shared_mutex m_heap_mtx; shared_mutex m_heap_map_mtx; void *m_heap_next = this + 1; utils::kmultimap m_free_heap; utils::kmultimap m_used_node; UmtxChain m_umtx_chains[2][c_umtx_chains]{}; std::atomic m_tsc_freq{0}; shared_mutex m_thread_id_mtx; OwningIdMap m_thread_id_map; mutable shared_mutex m_proc_mtx; utils::LinkedNode *m_processes = nullptr; shared_mutex m_evf_mtx; utils::kmap> m_event_flags; shared_mutex m_sem_mtx; utils::kmap> m_semaphores; shared_mutex mIpmiServerMtx; utils::kmap> mIpmiServers; shared_mutex m_kenv_mtx; utils::kmap m_kenv; // max size: 127 + '\0' }; extern KernelContext &g_context; } // namespace orbis