From 0311f06aa3a4aa0759ebcc34f5f90e6690cbbf96 Mon Sep 17 00:00:00 2001 From: SwareJonge Date: Sun, 19 Feb 2023 23:26:52 +0100 Subject: [PATCH] Add JKRHeap.cpp --- common.py | 14 + config/dol_slices.yml | 5 + config/symbols.yml | 18 +- configure.py | 3 + include/JSystem/JKernel/JKRDisposer.h | 21 ++ include/JSystem/JKernel/JKRHeap.h | 288 +++++++++++++++++ include/JSystem/JSupport/JSUList.h | 223 ++++++++++++++ include/JSystem/JUT/JUTAssertion.h | 25 +- include/dolphin/OS/OSAddress.h | 32 ++ include/dolphin/OS/OSAlloc.h | 15 + include/dolphin/OS/OSMutex.h | 36 +++ include/dolphin/OS/OSThread.h | 129 ++++++++ include/dolphin/OS/OSUtil.h | 18 ++ include/dolphin/OS/os.h | 5 +- src/JSystem/JKernel/JKRHeap.cpp | 426 ++++++++++++++++++++++++++ 15 files changed, 1255 insertions(+), 3 deletions(-) create mode 100644 include/JSystem/JKernel/JKRDisposer.h create mode 100644 include/JSystem/JKernel/JKRHeap.h create mode 100644 include/JSystem/JSupport/JSUList.h create mode 100644 include/dolphin/OS/OSAddress.h create mode 100644 include/dolphin/OS/OSAlloc.h create mode 100644 include/dolphin/OS/OSMutex.h create mode 100644 include/dolphin/OS/OSThread.h create mode 100644 include/dolphin/OS/OSUtil.h create mode 100644 src/JSystem/JKernel/JKRHeap.cpp diff --git a/common.py b/common.py index 383582fd..cbe130aa 100644 --- a/common.py +++ b/common.py @@ -332,7 +332,21 @@ SDK_CFLAG = [ ALIGN16_CFLAG = [ "-func_align 16", ] +JSYSTEM_BASE = [ + "-lang=c++", + "-inline on", + "-fp fmadd", + "-fp_contract on", + "-pool off", + "-Cpp_exceptions off", + "-RTTI on", + "-char signed", + "-enum int", + "-sym on", # might also be on for base flags? + "-O4,s" # in mkdd some libraries use O4,p, might be the case here too +] +JSYSTEM_CFLAGS = ' '.join(JSYSTEM_BASE + LOCAL_CFLAGS) DOL_CFLAGS = ' '.join(BASE_DOL_CFLAGS + LOCAL_CFLAGS) SDK_FLAGS = ' '.join(SDK_CFLAG + LOCAL_CFLAGS) ALIGN16 = ' '.join(BASE_DOL_CFLAGS + LOCAL_CFLAGS + ALIGN16_CFLAG) diff --git a/config/dol_slices.yml b/config/dol_slices.yml index 2e1c13fa..ef5224dd 100644 --- a/config/dol_slices.yml +++ b/config/dol_slices.yml @@ -4,6 +4,11 @@ libultra/gfxprint/gfxprint_locate8x8.c: .text: [0x8005B210, 0x8005B238] libforest/ReconfigBATs.c: .text: [0x8005adac, 0x8005aed4] +JSystem/JKernel/JKRHeap.cpp: + .text: [0x80063748, 0x80064028] + .data: [0x800ddf20, 0x800ddf98] + .sdata: [0x80217e58, 0x80217e80] + .sbss: [0x802186d8, 0x80218700] dolphin/BASE/ppcarch.c: .text: [0x8007867c, 0x80078718] dolphin/OS/OSArena.c: diff --git a/config/symbols.yml b/config/symbols.yml index b1abad27..b3cbc146 100644 --- a/config/symbols.yml +++ b/config/symbols.yml @@ -2624,7 +2624,23 @@ global: 0x8009ae00: __save_fpr 0x8009ae4c: __restore_fpr 0x8009ae98: __save_gpr - 0x8009aee4: __restore_gpr + 0x8009aeb8: _savegpr_22 + 0x8009aebc: _savegpr_23 + 0x8009aec0: _savegpr_24 + 0x8009aec4: _savegpr_25 + 0x8009aec8: _savegpr_26 + 0x8009aecc: _savegpr_27 + 0x8009aed0: _savegpr_28 + 0x8009aed4: _savegpr_29 + 0x8009aee4: __restore_gpr + 0x8009af04: _restgpr_22 + 0x8009af08: _restgpr_23 + 0x8009af0c: _restgpr_24 + 0x8009af10: _restgpr_25 + 0x8009af14: _restgpr_26 + 0x8009af18: _restgpr_27 + 0x8009af1c: _restgpr_28 + 0x8009af20: _restgpr_29 0x8009af30: __div2u 0x8009b01c: __div2i 0x8009b154: __mod2u diff --git a/configure.py b/configure.py index c96b5b34..7da3cae4 100644 --- a/configure.py +++ b/configure.py @@ -577,6 +577,9 @@ class CSource(Source): if path.startswith("src/dolphin/"): self.cflags = c.SDK_FLAGS self.cc = c.OCC + elif path.startswith("src/JSystem/JKernel/"): + self.cflags = c.JSYSTEM_CFLAGS + self.cc = c.CC elif path.startswith("src/jaudio_NES"): self.cc = c.CC self.cflags = c.DOL_CPPFLAGS diff --git a/include/JSystem/JKernel/JKRDisposer.h b/include/JSystem/JKernel/JKRDisposer.h new file mode 100644 index 00000000..9a4ced98 --- /dev/null +++ b/include/JSystem/JKernel/JKRDisposer.h @@ -0,0 +1,21 @@ +#ifndef JKRDISPOSER_H +#define JKRDISPOSER_H + +#include "types.h" + +#include "JSystem/JSupport/JSUList.h" + +class JKRHeap; + +class JKRDisposer +{ +public: + JKRDisposer(); + virtual ~JKRDisposer(); + +public: + JKRHeap *mRootHeap; // _4 + JSULink mPointerLinks; // _8 +}; + +#endif \ No newline at end of file diff --git a/include/JSystem/JKernel/JKRHeap.h b/include/JSystem/JKernel/JKRHeap.h new file mode 100644 index 00000000..4d75f54d --- /dev/null +++ b/include/JSystem/JKernel/JKRHeap.h @@ -0,0 +1,288 @@ +#ifndef JKRHEAP_H +#define JKRHEAP_H + +#include "dolphin/OS/OSMutex.h" +#include "JSystem/JKernel/JKRDisposer.h" + +#include "types.h" + +typedef void JKRHeapErrorHandler(void *, u32, int); + +class JKRHeap : public JKRDisposer +{ +public: + enum EAllocMode + { + HEAPALLOC_Unk1 = 1, + }; + + struct TState + { // NB: this struct doesn't agree with TP's struct + struct TLocation + { + TLocation() : _00(nullptr), _04(-1) + { + } + + void *_00; // _00 + int _04; // _04 + }; + + struct TArgument + { + TArgument(const JKRHeap *heap, u32 p2, bool p3) + : mHeap((heap) ? heap : JKRHeap::sCurrentHeap), mId(p2), mIsCompareOnDestructed(p3) + { + } + + const JKRHeap *mHeap; // _00 + u32 mId; // _04 + bool mIsCompareOnDestructed; // _08 + }; + + TState(const JKRHeap *heap, u32 id, bool isCompareOnDestructed) + : mUsedSize(0), mCheckCode(0), mArgument(heap, id, isCompareOnDestructed) + { + mArgument.mHeap->state_register(this, mArgument.mId); + } + + TState(JKRHeap *heap) + : mUsedSize(0), mCheckCode(0), mArgument(heap, 0xFFFFFFFF, true) + { + } + + ~TState(); + void dump() const { mArgument.mHeap->state_dump(*this); } + bool isVerbose() { return bVerbose_; }; + bool isCompareOnDestructed() const { return mArgument.mIsCompareOnDestructed; }; + u32 getUsedSize() const { return mUsedSize; } + u32 getCheckCode() const { return mCheckCode; } + const JKRHeap *getHeap() const { return mArgument.mHeap; } + u32 getId() const { return mArgument.mId; } + + // unused/inlined: + TState(const JKRHeap::TState::TArgument &arg, const JKRHeap::TState::TLocation &location); + TState(const JKRHeap::TState &other, bool p2); + TState(const JKRHeap::TState &other, const JKRHeap::TState::TLocation &location, bool p3); + + static bool bVerbose_; + + u32 mUsedSize; // _00 + u32 mCheckCode; // _04, plausibly TLocation when combined with _00 + u32 mBuf; // _08 + u8 _0C[0x4]; // _0C + TArgument mArgument; // _10 + TLocation mLocation; // _1C + }; + +public: + JKRHeap(void *, u32, JKRHeap *, bool); + + bool setErrorFlag(bool errorFlag); + bool isSubHeap(JKRHeap *heap) const; + + virtual ~JKRHeap(); + virtual void callAllDisposer(); + virtual void *do_alloc(u32, int) = 0; + virtual void do_free(void *) = 0; + virtual void do_freeAll() = 0; + virtual void do_freeTail() = 0; + virtual s32 do_resize(void *, u32) = 0; + virtual s32 do_getSize(void *) = 0; + virtual s32 do_getFreeSize() = 0; + virtual s32 do_getTotalFreeSize() = 0; + virtual u32 getHeapType() = 0; + virtual bool check() = 0; + virtual bool dump_sort() { return true; } + virtual bool dump() = 0; + virtual s32 do_changeGroupID(u8 newGroupID) { return 0; } + virtual u8 do_getCurrentGroupId() { return 0; } + virtual void state_register(JKRHeap::TState *, u32) const; + virtual bool state_compare(JKRHeap::TState const &, JKRHeap::TState const &) const; + virtual void state_dump(JKRHeap::TState const &) const; + + JKRHeap *becomeSystemHeap(); + JKRHeap *becomeCurrentHeap(); + void destroy(); + void *alloc(u32, int); + void free(void *); + void freeAll(); + void freeTail(); + void fillFreeArea(); + void resize(void *, u32); + static s32 getSize(void *, JKRHeap*); + + // ... more functions + + s32 getSize(void *ptr); + s32 getFreeSize(); + void *getMaxFreeBlock(); + s32 getTotalFreeSize(); + u8 getCurrentGroupId(); + s32 changeGroupID(u8 newGroupId); + u32 getMaxAllocatableSize(int alignment); + JKRHeap *find(void *) const; // 0x80084640 + JKRHeap *findAllHeap(void *) const; // 0x8008492c + void dispose_subroutine(u32 begin, u32 end); + bool dispose(void *, u32); // 0x80084b9c + void dispose(void *, void *); // 0x80084c2c + void dispose(); // 0x80084cb8 + + void appendDisposer(JKRDisposer *disposer) + { + mDisposerList.append(&disposer->mPointerLinks); + } + + void removeDisposer(JKRDisposer *disposer) + { + mDisposerList.remove(&disposer->mPointerLinks); + } + + void setDebugFill(bool debugFill) { mDebugFill = debugFill; } + bool getDebugFill() const { return mDebugFill; } + void *getStartAddr() const { return (void *)mStart; } + void *getEndAddr() const { return (void *)mEnd; } + u32 getHeapSize() const { return mSize; } + bool getErrorFlag() const { return mErrorFlag; } + void callErrorHandler(JKRHeap *heap, u32 size, int alignment) + { + if (mErrorHandler) + { + (*mErrorHandler)(heap, size, alignment); + } + } + + // Unused + void checkMemoryFilled(u8 *, u32 size, u8); + + static void destroy(JKRHeap *heap); // fabricated + static bool initArena(char **, u32 *, int); + static void *alloc(u32, int, JKRHeap *); + static void copyMemory(void *, void *, u32); + static void free(void *, JKRHeap *); + static void state_dumpDifference(const TState &, const TState &); + static JKRHeap *findFromRoot(void *); + static JKRHeapErrorHandler *setErrorHandler(JKRHeapErrorHandler *); + + static void *getCodeStart() + { + return mCodeStart; + } + + static void *getCodeEnd() + { + return mCodeEnd; + } + + static void *getUserRamStart() + { + return mUserRamStart; + } + + static void *getUserRamEnd() + { + return mUserRamEnd; + } + + static u32 getMemorySize() + { + return mMemorySize; + } + + static JKRHeap *getCurrentHeap() + { + return sCurrentHeap; + } + + static JKRHeap *getRootHeap() + { + return sRootHeap; + } + + static JKRHeap *getSystemHeap() + { + return sSystemHeap; + } + + static void *mCodeStart; + static void *mCodeEnd; + static void *mUserRamStart; + static void *mUserRamEnd; + static u32 mMemorySize; + + static JKRHeap *sSystemHeap; + static JKRHeap *sCurrentHeap; + static JKRHeap *sRootHeap; + + static bool sDefaultFillFlag; + static bool sDefaultFillCheckFlag; + + static JKRHeapErrorHandler *mErrorHandler; + +protected: + /* 0x00 */ // vtable + /* 0x04 */ // JKRDisposer + /* 0x18 */ OSMutex mMutex; + /* 0x30 */ void *mStart; + /* 0x34 */ void *mEnd; + /* 0x38 */ u32 mSize; + /* 0x3C */ bool mDebugFill; + /* 0x3D */ bool mCheckMemoryFilled; + /* 0x3E */ u8 mAllocationMode; // EAllocMode? + /* 0x3F */ u8 mGroupId; + /* 0x40 */ JSUTree mChildTree; + /* 0x5C */ JSUList mDisposerList; + /* 0x68 */ bool mErrorFlag; + /* 0x69 */ bool mInitFlag; + /* 0x6A */ u8 padding_0x6a[2]; +}; + +inline JKRHeap *JKRGetCurrentHeap() +{ + return JKRHeap::getCurrentHeap(); +} + +inline JKRHeap *JKRGetSystemHeap() +{ + return JKRHeap::getSystemHeap(); +} + +inline JKRHeap *JKRGetRootHeap() +{ + return JKRHeap::getRootHeap(); +} + +inline void *JKRAllocFromSysHeap(u32 size, int alignment) +{ + return JKRHeap::getSystemHeap()->alloc(size, alignment); +} + +inline void *JKRAllocFromHeap(JKRHeap *heap, u32 size, int alignment) +{ + return JKRHeap::alloc(size, alignment, heap); +} + +inline void JKRFree(void *pBuf) +{ + JKRHeap::free(pBuf, nullptr); +} + +inline void JKRFreeToSysHeap(void *buf) +{ + JKRHeap::getSystemHeap()->free(buf); +} + +void JKRDefaultMemoryErrorRoutine(void *, u32, int); + +void *operator new(size_t); +void *operator new(size_t, s32); +void *operator new(size_t, JKRHeap *, int); + +void *operator new[](size_t); +void *operator new[](size_t, s32); +void *operator new[](size_t, JKRHeap *, int); + +void operator delete(void *); +void operator delete[](void *); + +#endif // !JKRHEAP_H diff --git a/include/JSystem/JSupport/JSUList.h b/include/JSystem/JSupport/JSUList.h new file mode 100644 index 00000000..0dcf2ab1 --- /dev/null +++ b/include/JSystem/JSupport/JSUList.h @@ -0,0 +1,223 @@ +#ifndef JSULIST_H +#define JSULIST_H + +#include "types.h" + +class JSUPtrLink; + +class JSUPtrList +{ +public: + JSUPtrList() + { + initiate(); + } + + JSUPtrList(bool); + ~JSUPtrList(); + + void initiate(); + void setFirst(JSUPtrLink *); + bool append(JSUPtrLink *); + bool prepend(JSUPtrLink *); + bool insert(JSUPtrLink *, JSUPtrLink *); + bool remove(JSUPtrLink *); + JSUPtrLink *getNthLink(u32 idx) const; + + JSUPtrLink *getFirstLink() const { return mHead; } + JSUPtrLink *getLastLink() const { return mTail; } + u32 getNumLinks() const { return mLinkCount; } + + JSUPtrLink *mHead; // _0 + JSUPtrLink *mTail; // _4 + u32 mLinkCount; // _8 +}; + +class JSUPtrLink +{ +public: + JSUPtrLink(void *); + ~JSUPtrLink(); + + void *getObjectPtr() const { return mData; } + JSUPtrList *getList() const { return mPtrList; } + JSUPtrLink *getNext() const { return mNext; } + JSUPtrLink *getPrev() const { return mPrev; } + + void *mData; // _0 + JSUPtrList *mPtrList; // _4 + JSUPtrLink *mPrev; // _8 + JSUPtrLink *mNext; // _C +}; + +template +class JSULink; // friend class? i'm C++ noob + +template +class JSUList : public JSUPtrList +{ +public: + JSUList(bool thing) : JSUPtrList(thing) + { + } + JSUList() : JSUPtrList() + { + } + + bool append(JSULink *link) { return JSUPtrList::append((JSUPtrLink *)link); } + bool prepend(JSULink *link) { return JSUPtrList::prepend((JSUPtrLink *)link); } + bool insert(JSULink *before, JSULink *link) { return JSUPtrList::insert((JSUPtrLink *)before, (JSUPtrLink *)link); } + bool remove(JSULink *link) { return JSUPtrList::remove((JSUPtrLink *)link); } + + JSULink *getFirst() const { return (JSULink *)getFirstLink(); } + JSULink *getLast() const { return (JSULink *)getLastLink(); } + JSULink *getEnd() const { return nullptr; } + + u32 getNumLinks() const { return mLinkCount; } +}; + +template +class JSUListIterator +{ +public: + JSUListIterator() + : mLink(nullptr) + { + } + JSUListIterator(JSULink *link) + : mLink(link) + { + } + JSUListIterator(JSUList *list) + : mLink(list->getFirst()) + { + } + + JSUListIterator &operator=(JSULink *link) + { + this->mLink = link; + return *this; + } + + T *getObject() { return this->mLink->getObject(); } + + bool operator==(JSULink const *other) const { return this->mLink == other; } + bool operator!=(JSULink const *other) const { return this->mLink != other; } + bool operator==(JSUListIterator const &other) const { return this->mLink == other.mLink; } + bool operator!=(JSUListIterator const &other) const { return this->mLink != other.mLink; } + + JSUListIterator operator++(int) + { + JSUListIterator prev = *this; + this->mLink = this->mLink->getNext(); + return prev; + } + + JSUListIterator &operator++() + { + this->mLink = this->mLink->getNext(); + return *this; + } + + JSUListIterator operator--(int) + { + JSUListIterator prev = *this; + this->mLink = this->mLink->getPrev(); + return prev; + } + + JSUListIterator &operator--() + { + this->mLink = this->mLink->getPrev(); + return *this; + } + + T &operator*() { return *this->getObject(); } + + T *operator->() { return this->getObject(); } + + // private: + JSULink *mLink; +}; + +template +class JSULink : public JSUPtrLink +{ +public: + JSULink(void *pData) : JSUPtrLink(pData) + { + } + + T *getObject() const { return (T *)mData; } + JSUList *getList() const { return (JSUList *)JSUPtrLink::getList(); } // fabricated, offcial name: getSupervisor + JSULink *getNext() const { return (JSULink *)JSUPtrLink::getNext(); } + JSULink *getPrev() const { return (JSULink *)JSUPtrLink::getPrev(); } + + ~JSULink() + { + } +}; + +template // TODO: most of these inlines are probably wrong: rework +class JSUTree : public JSUList, public JSULink +{ +public: + JSUTree(T *owner) : JSUList(), JSULink(owner) {} + ~JSUTree() {} + + bool appendChild(JSUTree *child) { return this->append(child); } + bool prependChild(JSUTree *child) { return this->prepend(child); } + bool removeChild(JSUTree *child) { return this->remove(child); } + bool insertChild(JSUTree *before, JSUTree *child) { return this->insert(before, child); } + + JSUTree *getEndChild() const { return nullptr; } + JSUTree *getFirstChild() const { return (JSUTree *)getFirstLink(); } + JSUTree *getLastChild() const { return (JSUTree *)this->getLast(); } + JSUTree *getNextChild() const { return (JSUTree *)mNext; } + JSUTree *getPrevChild() const { return (JSUTree *)this->getPrev(); } + u32 getNumChildren() const { return mLinkCount; } + T *getObject() const { return (T *)this->mData; } + JSUTree *getParent() const { return (JSUTree *)this->mPtrList; } +}; + +template +class JSUTreeIterator +{ +public: + JSUTreeIterator() : mTree(nullptr) {} + JSUTreeIterator(JSUTree *tree) : mTree(tree) {} + + JSUTreeIterator &operator=(JSUTree *tree) + { + this->mTree = tree; + return *this; + } + + T *getObject() const { return mTree->getObject(); } + + bool operator==(JSUTree *other) { return this->mTree == other; } + + bool operator!=(const JSUTree *other) const { return this->mTree != other; } + + JSUTreeIterator operator++(int) + { + JSUTreeIterator prev = *this; + this->mTree = this->mTree->getNextChild(); + return prev; + } + + JSUTreeIterator &operator++() + { + this->mTree = this->mTree->getNextChild(); + return *this; + } + + T &operator*() { return *this->getObject(); } + + T *operator->() const { return mTree->getObject(); } + +private: + JSUTree *mTree; +}; + +#endif /* JSULIST_H */ \ No newline at end of file diff --git a/include/JSystem/JUT/JUTAssertion.h b/include/JSystem/JUT/JUTAssertion.h index 9a3f600a..405f1c63 100644 --- a/include/JSystem/JUT/JUTAssertion.h +++ b/include/JSystem/JUT/JUTAssertion.h @@ -1,6 +1,29 @@ #ifndef _JSYSTEM_JUT_JUTASSERTION_H #define _JSYSTEM_JUT_JUTASSERTION_H -void JC_JUTAssertion_changeDevice(u32); +#include "types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +void JC_JUTAssertion_changeDevice(u32); + +#define JUT_PANIC(...) +#define JUT_PANIC_F(...) +#define JUT_CONFIRM_MESSAGE(...) +#define JUT_WARNING(...) +#define JUT_WARNING_F(...) +#define JUT_ASSERT(...) +#define JUT_ASSERT_F(...) +#define JUT_ASSERT_MSG(...) +#define JUT_MINMAX_ASSERT(...) +#define JUT_MAX_ASSERT(...) +#define JUT_LOG_F(...) + +#ifdef __cplusplus +} +#endif #endif diff --git a/include/dolphin/OS/OSAddress.h b/include/dolphin/OS/OSAddress.h new file mode 100644 index 00000000..2888e45e --- /dev/null +++ b/include/dolphin/OS/OSAddress.h @@ -0,0 +1,32 @@ +#ifndef OS_ADDRESS_H +#define OS_ADDRESS_H + +// maybe put this in OSUtil instead +#include "types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Defines for cached and uncached memory. +#define OS_BASE_CACHED (0x80000000) +#define OS_BASE_UNCACHED (0xC0000000) + +// Address conversions. +#define OSPhysicalToCached(paddr) ((void *)((u32)(paddr) + OS_BASE_CACHED)) +#define OSPhysicalToUncached(paddr) ((void *)((u32)(paddr) + OS_BASE_UNCACHED)) +#define OSCachedToPhysical(caddr) ((u32)((u8 *)(caddr)-OS_BASE_CACHED)) +#define OSUncachedToPhysical(ucaddr) ((u32)((u8 *)(ucaddr)-OS_BASE_UNCACHED)) +#define OSCachedToUncached(caddr) ((void *)((u8 *)(caddr) + (OS_BASE_UNCACHED - OS_BASE_CACHED))) +#define OSUncachedToCached(ucaddr) ((void *)((u8 *)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED))) + +#define OS_CACHED_REGION_PREFIX 0x8000 +#define OS_UNCACHED_REGION_PREFIX 0xC000 +#define OS_PHYSICAL_MASK 0x3FFF + +#ifdef __cplusplus +}; +#endif + +#endif \ No newline at end of file diff --git a/include/dolphin/OS/OSAlloc.h b/include/dolphin/OS/OSAlloc.h new file mode 100644 index 00000000..e413f67f --- /dev/null +++ b/include/dolphin/OS/OSAlloc.h @@ -0,0 +1,15 @@ +#ifndef OS_ALLOC_H +#define OS_ALLOC_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + void *OSInitAlloc(void *, void *, int); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/include/dolphin/OS/OSMutex.h b/include/dolphin/OS/OSMutex.h new file mode 100644 index 00000000..659ec972 --- /dev/null +++ b/include/dolphin/OS/OSMutex.h @@ -0,0 +1,36 @@ +#ifndef OS_MUTEX_H +#define OS_MUTEX_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "dolphin/OS/OSThread.h" + + struct OSMutex + { + OSThreadQueue queue; + OSThread *thread; // the current owner + s32 count; // lock count + OSMutexLink link; // for OSThread.queueMutex + }; + + struct OSCond + { + OSThreadQueue queue; + }; + + void OSInitMutex(OSMutex *mutex); + void OSLockMutex(OSMutex *mutex); + void OSUnlockMutex(OSMutex *mutex); + BOOL OSTryLockMutex(OSMutex *mutex); + void OSInitCond(OSCond *cond); + void OSWaitCond(OSCond *cond, OSMutex *mutex); + void OSSignalCond(OSCond *cond); + +#ifdef __cplusplus +} +#endif + +#endif // DOLPHIN_OSMUTEX_H diff --git a/include/dolphin/OS/OSThread.h b/include/dolphin/OS/OSThread.h new file mode 100644 index 00000000..19193659 --- /dev/null +++ b/include/dolphin/OS/OSThread.h @@ -0,0 +1,129 @@ +#ifndef OS_THREAD_H +#define OS_THREAD_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "dolphin/os/OSContext.h" + + typedef struct OSThread OSThread; + typedef struct OSThreadQueue OSThreadQueue; + typedef struct OSThreadLink OSThreadLink; + typedef s32 OSPriority; // 0 highest, 31 lowest + + typedef struct OSMutex OSMutex; + typedef struct OSMutexQueue OSMutexQueue; + typedef struct OSMutexLink OSMutexLink; + typedef struct OSCond OSCond; + + typedef void (*OSIdleFunction)(void *param); + + struct OSThreadQueue + { + OSThread *head; + OSThread *tail; + }; + + struct OSThreadLink + { + OSThread *next; + OSThread *prev; + }; + + struct OSMutexQueue + { + OSMutex *head; + OSMutex *tail; + }; + + struct OSMutexLink + { + OSMutex *next; + OSMutex *prev; + }; + + struct OSThread + { + OSContext context; // register context + + u16 state; // OS_THREAD_STATE_* + u16 attr; // OS_THREAD_ATTR_* + s32 suspend; // suspended if the count is greater than zero + OSPriority priority; // effective scheduling priority + OSPriority base; // base scheduling priority + void *val; // exit value + + OSThreadQueue *queue; // queue thread is on + OSThreadLink link; // queue link + + OSThreadQueue queueJoin; // list of threads waiting for termination (join) + + OSMutex *mutex; // mutex trying to lock + OSMutexQueue queueMutex; // list of mutexes owned + + OSThreadLink linkActive; // link of all threads for debugging + + u8 *stackBase; // the thread's designated stack (high address) + u32 *stackEnd; // last word of stack (low address) + }; + + // Thread states + enum OS_THREAD_STATE + { + OS_THREAD_STATE_READY = 1, + OS_THREAD_STATE_RUNNING = 2, + OS_THREAD_STATE_WAITING = 4, + OS_THREAD_STATE_MORIBUND = 8 + }; + +// Thread priorities +#define OS_PRIORITY_MIN 0 // highest +#define OS_PRIORITY_MAX 31 // lowest +#define OS_PRIORITY_IDLE OS_PRIORITY_MAX + +// Thread attributes +#define OS_THREAD_ATTR_DETACH 0x0001u // detached + +// Stack magic value +#define OS_THREAD_STACK_MAGIC 0xDEADBABE + + void OSInitThreadQueue(OSThreadQueue *queue); + OSThread *OSGetCurrentThread(void); + BOOL OSIsThreadSuspended(OSThread *thread); + BOOL OSIsThreadTerminated(OSThread *thread); + s32 OSDisableScheduler(void); + s32 OSEnableScheduler(void); + void OSYieldThread(void); + BOOL OSCreateThread(OSThread *thread, + void *(*func)(void *), + void *param, + void *stack, + u32 stackSize, + OSPriority priority, + u16 attr); + void OSExitThread(void *val); + void OSCancelThread(OSThread *thread); + BOOL OSJoinThread(OSThread *thread, void **val); + void OSDetachThread(OSThread *thread); + s32 OSResumeThread(OSThread *thread); + s32 OSSuspendThread(OSThread *thread); + BOOL OSSetThreadPriority(OSThread *thread, OSPriority priority); + OSPriority OSGetThreadPriority(OSThread *thread); + void OSSleepThread(OSThreadQueue *queue); + void OSWakeupThread(OSThreadQueue *queue); + + OSThread *OSSetIdleFunction(OSIdleFunction idleFunction, + void *param, + void *stack, + u32 stackSize); + OSThread *OSGetIdleFunction(void); + + long OSCheckActiveThreads(void); + +#ifdef __cplusplus +} +#endif + +#endif // DOLPHIN_OSTHREAD_H diff --git a/include/dolphin/OS/OSUtil.h b/include/dolphin/OS/OSUtil.h new file mode 100644 index 00000000..70f5071a --- /dev/null +++ b/include/dolphin/OS/OSUtil.h @@ -0,0 +1,18 @@ +#ifndef OS_UTIL_H +#define OS_UTIL_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define OSRoundUp32B(x) (((u32)(x) + 0x1F) & ~(0x1F)) +#define OSRoundDown32B(x) (((u32)(x)) & ~(0x1F)) + +#ifdef __cplusplus +}; +#endif + +#endif \ No newline at end of file diff --git a/include/dolphin/OS/os.h b/include/dolphin/OS/os.h index 37ce2b6b..1e1ccde1 100644 --- a/include/dolphin/OS/os.h +++ b/include/dolphin/OS/os.h @@ -8,14 +8,17 @@ extern "C" { #endif +void OSPanic(const char *file, int line, const char *message, ...); void OSReport(const char*, ...); void OSVReport(const char* format, va_list list); +#define OSErrorLine(line, ...) \ + OSPanic(__FILE__, line, __VA_ARGS__) + asm BOOL OSDisableInterrupts(void); asm BOOL OSEnableInterrupts(void); asm BOOL OSRestoreInterrupts(BOOL level); - void __RAS_OSDisableInterrupts_begin(void); void __RAS_OSDisableInterrupts_end(void); diff --git a/src/JSystem/JKernel/JKRHeap.cpp b/src/JSystem/JKernel/JKRHeap.cpp new file mode 100644 index 00000000..bf96d780 --- /dev/null +++ b/src/JSystem/JKernel/JKRHeap.cpp @@ -0,0 +1,426 @@ +#include "JSystem/JUT/JUTAssertion.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "dolphin/OS/os.h" +#include "dolphin/OS/OSArena.h" +#include "dolphin/OS/OSAlloc.h" +#include "dolphin/OS/OSMemory.h" +#include "dolphin/OS/OSUtil.h" +#include "dolphin/OS/OSAddress.h" + +JKRHeap *JKRHeap::sSystemHeap; +JKRHeap *JKRHeap::sCurrentHeap; +JKRHeap *JKRHeap::sRootHeap; +JKRHeapErrorHandler *JKRHeap::mErrorHandler; +void *JKRHeap::mCodeStart; +void *JKRHeap::mCodeEnd; +void *JKRHeap::mUserRamStart; +void *JKRHeap::mUserRamEnd; +u32 JKRHeap::mMemorySize; + +bool JKRHeap::sDefaultFillFlag = true; + +JKRHeap::JKRHeap(void *data, u32 size, JKRHeap *heap, bool errorFlag) : JKRDisposer(), + mChildTree(this), + mDisposerList() +{ + OSInitMutex(&mMutex); + mSize = size; + mStart = (u8 *)data; + mEnd = ((u8 *)data + size); + if (heap == nullptr) + { + becomeSystemHeap(); + becomeCurrentHeap(); + } + else + { + heap->mChildTree.appendChild(&mChildTree); + if (sSystemHeap == sRootHeap) + becomeSystemHeap(); + if (sCurrentHeap == sRootHeap) + becomeCurrentHeap(); + } + mErrorFlag = errorFlag; + if (mErrorFlag == true && mErrorHandler == nullptr) + mErrorHandler = JKRDefaultMemoryErrorRoutine; + mDebugFill = sDefaultFillFlag; + mInitFlag = false; +} + +JKRHeap::~JKRHeap() +{ + mChildTree.getParent()->removeChild(&mChildTree); + JSUTree *nextRootHeap = sRootHeap->mChildTree.getFirstChild(); + if (sCurrentHeap == this) + sCurrentHeap = !nextRootHeap ? sRootHeap : nextRootHeap->getObject(); + + if (sSystemHeap == this) + sSystemHeap = !nextRootHeap ? sRootHeap : nextRootHeap->getObject(); +} + +bool JKRHeap::initArena(char **outUserRamStart, u32 *outUserRamSize, int numHeaps) +{ + void *arenaLo = OSGetArenaLo(); + void *arenaHi = OSGetArenaHi(); + if (arenaLo == arenaHi) + { + return false; + } + void *arenaStart = OSInitAlloc(arenaLo, arenaHi, numHeaps); + arenaHi = (u8 *)OSRoundDown32B(arenaHi); + arenaLo = (u8 *)OSRoundUp32B(arenaStart); + u8 *start = (u8 *)OSPhysicalToCached(0); + mCodeStart = (u8 *)start; + mCodeEnd = (u8 *)arenaLo; + mUserRamStart = (u8 *)arenaLo; + mUserRamEnd = (u8 *)arenaHi; + mMemorySize = *(u32 *)((start + 0x28)); + OSSetArenaLo(arenaHi); + OSSetArenaHi(arenaHi); + *outUserRamStart = (char *)arenaLo; + *outUserRamSize = (u32)arenaHi - (u32)arenaLo; + return true; +} + +JKRHeap *JKRHeap::becomeSystemHeap() +{ + JKRHeap *old = sSystemHeap; + sSystemHeap = this; + return old; +} + +JKRHeap *JKRHeap::becomeCurrentHeap() +{ + JKRHeap *old = sCurrentHeap; + sCurrentHeap = this; + return old; +} + +void JKRHeap::destroy(JKRHeap *heap) +{ + JUT_ASSERT(200, heap != 0); + heap->destroy(); +} + +void *JKRHeap::alloc(u32 byteCount, int padding, JKRHeap *heap) +{ + void *memory = nullptr; + if (heap) + { + memory = heap->do_alloc(byteCount, padding); + } + else if (sCurrentHeap) + { + memory = sCurrentHeap->do_alloc(byteCount, padding); + } + return memory; +} + +void *JKRHeap::alloc(u32 byteCount, int padding) +{ + JUT_WARNING_F(317, !mInitFlag, "alloc %x byte in heap %x", byteCount, this); + return do_alloc(byteCount, padding); +} + +void JKRHeap::free(void *memory, JKRHeap *heap) +{ + if ((heap) || (heap = findFromRoot(memory), heap)) + { + heap->free(memory); + } +} + +void JKRHeap::free(void *memory) +{ + JUT_WARNING_F(365, !mInitFlag, "free %x in heap %x", memory, this); + do_free(memory); +} + +void JKRHeap::callAllDisposer() +{ + JSUListIterator iterator; + while (iterator = mDisposerList.getFirst(), iterator != mDisposerList.getEnd()) + { + iterator->~JKRDisposer(); + } +} + +void JKRHeap::freeAll() +{ + JUT_WARNING_F(417, !mInitFlag, "freeAll in heap %x", this); + do_freeAll(); +} + +void JKRHeap::freeTail() +{ + JUT_WARNING_F(431, !mInitFlag, "freeTail in heap %x", this); + do_freeTail(); +} + +void JKRHeap::resize(void *memoryBlock, u32 newSize) +{ + JUT_WARNING_F(491, !mInitFlag, "resize block %x into %x in heap %x", memoryBlock, newSize, this); + do_resize(memoryBlock, newSize); +} + +s32 JKRHeap::getSize(void *memoryBlock, JKRHeap *heap) +{ + if (heap == nullptr && (heap = findFromRoot(memoryBlock), heap == nullptr)) + { + return -1; + } + else + return heap->getSize(memoryBlock); +} + +s32 JKRHeap::getSize(void *memoryBlock) { return do_getSize(memoryBlock); } +s32 JKRHeap::getFreeSize() { return do_getFreeSize(); } +s32 JKRHeap::getTotalFreeSize() { return do_getTotalFreeSize(); } + +s32 JKRHeap::changeGroupID(u8 newGroupID) +{ + JUT_WARNING_F(570, !mInitFlag, "change heap ID into %x in heap %x", newGroupID, this); + return do_changeGroupID(newGroupID); +} + +u8 JKRHeap::getCurrentGroupId() { return do_getCurrentGroupId(); } + +JKRHeap *JKRHeap::findFromRoot(void *ptr) +{ + if (sRootHeap != nullptr) + return sRootHeap->find(ptr); + + return nullptr; +} + +JKRHeap *JKRHeap::find(void *memory) const +{ + if ((mStart <= memory) && (memory <= mEnd)) + { + if (mChildTree.getNumChildren() != 0) + { + for (JSUTreeIterator iterator(mChildTree.getFirstChild()); iterator != mChildTree.getEndChild(); ++iterator) + { + JKRHeap *result = iterator->find(memory); + if (result) + { + return result; + } + } + } + return const_cast(this); + } + return nullptr; +} + +JKRHeap *JKRHeap::findAllHeap(void *memory) const +{ + if (mChildTree.getNumChildren() != 0) + { + for (JSUTreeIterator iterator(mChildTree.getFirstChild()); iterator != mChildTree.getEndChild(); ++iterator) + { + JKRHeap *result = iterator->findAllHeap(memory); + if (result) + { + return result; + } + } + } + + if (mStart <= memory && memory < mEnd) + { + return const_cast(this); + } + + return nullptr; +} + +// generates __as__25JSUTreeIterator<7JKRHeap>FP17JSUTree<7JKRHeap> and __ct__25JSUTreeIterator<7JKRHeap>Fv, remove this +void JKRHeap::dispose_subroutine(u32 begin, u32 end) +{ + JSUListIterator last_iterator; + JSUListIterator next_iterator; + JSUListIterator iterator; + for (iterator = mDisposerList.getFirst(); iterator != mDisposerList.getEnd(); + iterator = next_iterator) + { + JKRDisposer *disposer = iterator.getObject(); + + if ((void *)begin <= disposer && disposer < (void *)end) + { + disposer->~JKRDisposer(); + if (last_iterator == nullptr) + { + next_iterator = mDisposerList.getFirst(); + } + else + { + next_iterator = last_iterator; + next_iterator++; + } + } + else + { + last_iterator = iterator; + next_iterator = iterator; + next_iterator++; + } + } +} + +bool JKRHeap::dispose(void *memory, u32 size) +{ + u32 begin = (u32)memory; + u32 end = (u32)memory + size; + dispose_subroutine(begin, end); + return false; +} + +void JKRHeap::dispose(void *begin, void *end) +{ + dispose_subroutine((u32)begin, (u32)end); +} + +void JKRHeap::dispose() +{ + JSUListIterator iterator; + while (iterator = mDisposerList.getFirst(), iterator != mDisposerList.getEnd()) + { + iterator->~JKRDisposer(); + } +} + +void JKRHeap::copyMemory(void *dst, void *src, u32 size) +{ + u32 count = (size + 3) / 4; + + u32 *dst_32 = (u32 *)dst; + u32 *src_32 = (u32 *)src; + while (count > 0) + { + *dst_32 = *src_32; + dst_32++; + src_32++; + count--; + } +} + +void JKRDefaultMemoryErrorRoutine(void *heap, u32 size, int alignment) +{ + // OSReport("Error: Cannot allocate memory %d(0x%x)byte in %d byte alignment from %08x\n", size, size, alignment, heap); + OSErrorLine(710, "abort\n"); +} + +JKRHeapErrorHandler *JKRHeap::setErrorHandler(JKRHeapErrorHandler *newHandler) +{ + JKRHeapErrorHandler *oldHandler = mErrorHandler; + if (!newHandler) + { + newHandler = JKRDefaultMemoryErrorRoutine; + } + mErrorHandler = newHandler; + return oldHandler; +} + +bool JKRHeap::isSubHeap(JKRHeap *heap) const +{ + if (!heap) + return false; + + if (mChildTree.getNumChildren() != 0) + { + JSUTreeIterator iterator; + for (iterator = mChildTree.getFirstChild(); iterator != mChildTree.getEndChild(); ++iterator) + { + if (iterator.getObject() == heap) + { + return true; + } + + if (iterator.getObject()->isSubHeap(heap)) + { + return true; + } + } + } + + return false; +} + +void *operator new(u32 byteCount) +{ + return JKRHeap::alloc(byteCount, 4, nullptr); +} +void *operator new(u32 byteCount, int alignment) +{ + return JKRHeap::alloc(byteCount, alignment, nullptr); +} +void *operator new(u32 byteCount, JKRHeap *heap, int alignment) +{ + return JKRHeap::alloc(byteCount, alignment, heap); +} + +void *operator new[](u32 byteCount) +{ + return JKRHeap::alloc(byteCount, 4, nullptr); +} +void *operator new[](u32 byteCount, int alignment) +{ + return JKRHeap::alloc(byteCount, alignment, nullptr); +} +void *operator new[](u32 byteCount, JKRHeap *heap, int alignment) +{ + return JKRHeap::alloc(byteCount, alignment, heap); +} + +// this is not needed without the other pragma and asm bs +void operator delete(void *memory) { JKRHeap::free(memory, nullptr); } +void operator delete[](void *memory) { JKRHeap::free(memory, nullptr); } + +/*JKRHeap::TState::TState(const JKRHeap::TState::TArgument &arg, const JKRHeap::TState::TLocation &location) +{ + // UNUSED FUNCTION +} + +JKRHeap::TState::TState(const JKRHeap::TState &other, bool p2) +{ + // UNUSED FUNCTION +} + +JKRHeap::TState::TState(const JKRHeap::TState &other, const JKRHeap::TState::TLocation &location, bool p3) +{ + // UNUSED FUNCTION +}*/ + +JKRHeap::TState::~TState() +{ + // Unused, however might need it +} + +void JKRHeap::state_register(JKRHeap::TState *p, u32) const +{ + JUT_ASSERT(1132, p != 0); + JUT_ASSERT(1133, p->getHeap() == this); +} + +bool JKRHeap::state_compare(const JKRHeap::TState &r1, const JKRHeap::TState &r2) const +{ + JUT_ASSERT(1141, r1.getHeap() == r2.getHeap()); + return (r1.getCheckCode() == r2.getCheckCode()); +} + +// fabricated, but probably matches(except for line numbers) +void JKRHeap::state_dumpDifference(const JKRHeap::TState &r1, const JKRHeap::TState &r2) +{ + JUT_LOG_F(1157, "heap : %p / %p", r1.getHeap(), r2.getHeap()); + JUT_LOG_F(1158, "check-code : 0x%08x / 0x%08x", r1.getCheckCode(), r2.getCheckCode()); + JUT_LOG_F(1159, "id : 0x%08x / 0x%08x", r1.getId(), r2.getId()); + JUT_LOG_F(1160, "used size : %10u / %10u", r1.getUsedSize(), r2.getUsedSize()); +} + +void JKRHeap::state_dump(const TState &state) const +{ + JUT_LOG_F(1165, "check-code : 0x%08x", state.getCheckCode()); + JUT_LOG_F(1166, "id : 0x%08x", state.getId()); + JUT_LOG_F(1167, "used size : %u", state.getUsedSize()); +}