diff --git a/CMakeLists.txt b/CMakeLists.txt index 913b6a8..8bc512c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ option(AURORA_ENABLE_GX "Enable GX implementation and WebGPU renderer" ON) add_subdirectory(extern) include(cmake/aurora_core.cmake) +include(cmake/aurora_os.cmake) if (AURORA_ENABLE_GX) include(cmake/aurora_gx.cmake) endif () diff --git a/cmake/aurora_os.cmake b/cmake/aurora_os.cmake new file mode 100644 index 0000000..b3d613d --- /dev/null +++ b/cmake/aurora_os.cmake @@ -0,0 +1,13 @@ +add_library(aurora_os STATIC lib/dolphin/os/OSInit.cpp + lib/dolphin/os/OSMemory.cpp + lib/dolphin/os/internal.hpp + lib/dolphin/os/OSBootInfo.cpp + lib/dolphin/os/OSTime.cpp + lib/dolphin/os/OSArena.cpp + lib/dolphin/os/OSAddress.cpp + lib/dolphin/os/OSReport.cpp + lib/dolphin/AR.cpp) +add_library(aurora::os ALIAS aurora_os) + +target_include_directories(aurora_os PUBLIC include) +target_link_libraries(aurora_os PRIVATE aurora::core) diff --git a/examples/simple.c b/examples/simple.c index 6e229c5..cb8a6c4 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include diff --git a/include/aurora/aurora.h b/include/aurora/aurora.h index 185465c..75652fc 100644 --- a/include/aurora/aurora.h +++ b/include/aurora/aurora.h @@ -51,6 +51,9 @@ typedef struct AuroraEvent AuroraEvent; typedef void (*AuroraLogCallback)(AuroraLogLevel level, const char* module, const char* message, unsigned int len); typedef void (*AuroraImGuiInitCallback)(const AuroraWindowSize* size); +#define MEM1_DEFAULT_SIZE = 24 * 1024 * 1024; +#define ARAM_DEFAULT_SIZE = 16 * 1024 * 1024; + typedef struct { const char* appName; const char* configPath; @@ -68,6 +71,19 @@ typedef struct { uint32_t iconHeight; AuroraLogCallback logCallback; AuroraImGuiInitCallback imGuiInitCallback; + + /* + * The size of the GameCube's main memory, or MEM1 on the Wii. + * Note that it will not be allocated at the exact 0x80000000 address, as that cannot be guaranteed. + * This can be set to 0 to disable allocating this region. + */ + uint32_t mem1Size; + + /* + * The size of the GameCube's ARAM, or MEM2 on the Wii. + * This can be set to 0 to disable allocating this region. + */ + uint32_t mem2Size; } AuroraConfig; typedef struct { diff --git a/include/dolphin/os.h b/include/dolphin/os.h index 7ce3706..f96b1d6 100644 --- a/include/dolphin/os.h +++ b/include/dolphin/os.h @@ -70,8 +70,10 @@ typedef struct { #define OS_UNCACHED_REGION_PREFIX 0xC000 #define OS_PHYSICAL_MASK 0x3FFF -#define OS_BASE_CACHED (OS_CACHED_REGION_PREFIX << 16) -#define OS_BASE_UNCACHED (OS_UNCACHED_REGION_PREFIX << 16) +extern uintptr_t OSBaseAddress; + +#define OS_BASE_CACHED (OSBaseAddress) +#define OS_BASE_UNCACHED (OSBaseAddress) #ifdef __MWERKS__ u32 __OSPhysicalMemSize AT_ADDRESS(OS_BASE_CACHED | 0x0028); @@ -89,13 +91,14 @@ OSThread* __gUnkThread1 AT_ADDRESS(OS_BASE_CACHED | 0x00D8); int __gUnknown800030C0[2] AT_ADDRESS(OS_BASE_CACHED | 0x30C0); u8 __gUnknown800030E3 AT_ADDRESS(OS_BASE_CACHED | 0x30E3); #else -#define __OSBusClock 486000000 -#define __OSCoreClock (486000000 / 4) -#endif // __MWERKS__ +#define __OSBusClock (*(u32 *)(OS_BASE_CACHED + 0x00F8)) +#define __OSCoreClock (*(u32 *)(OS_BASE_CACHED + 0x00FC)) +#endif -#define OS_BUS_CLOCK __OSBusClock -#define OS_CORE_CLOCK __OSCoreClock -#define OS_TIMER_CLOCK (OS_BUS_CLOCK/4) +#define OS_TIMER_CLOCK_DIVIDER 4 +#define OS_BUS_CLOCK 150'000'000 +#define OS_CORE_CLOCK 150'000'000 +#define OS_TIMER_CLOCK (OS_BUS_CLOCK/OS_TIMER_CLOCK_DIVIDER) #define OSTicksToSeconds(ticks) ((ticks) / (OS_TIMER_CLOCK)) #define OSTicksToMilliseconds(ticks) ((ticks) / (OS_TIMER_CLOCK/1000)) @@ -122,7 +125,9 @@ void __OSPSInit(void); void __OSFPRInit(void); u32 __OSGetDIConfig(void); +#if 0 void OSDefaultExceptionHandler(__OSException exception, OSContext* context); +#endif typedef struct OSCalendarTime { /* 0x00 */ int sec; @@ -212,29 +217,6 @@ void OSFatal NORETURN(GXColor fg, GXColor bg, const char* msg); #define OSRoundUp32B(x) (((uintptr_t)(x) + 32 - 1) & ~(32 - 1)) #define OSRoundDown32B(x) (((uintptr_t)(x)) & ~(32 - 1)) -#ifdef TARGET_PC - -static inline void* OSPhysicalToCached(u32 paddr) { - return reinterpret_cast(static_cast(paddr)); -} -static inline void* OSPhysicalToUncached(u32 paddr) { - return reinterpret_cast(static_cast(paddr)); -} -static inline u32 OSCachedToPhysical(void* caddr) { - return static_cast(reinterpret_cast(caddr)); -} -static inline u32 OSUncachedToPhysical(void* ucaddr) { - return static_cast(reinterpret_cast(ucaddr)); -} -static inline void* OSCachedToUncached(void* caddr) { - return caddr; -} -static inline void* OSUncachedToCached(void* ucaddr) { - return ucaddr; -} - -#else // non-TARGET_PC - void* OSPhysicalToCached(u32 paddr); void* OSPhysicalToUncached(u32 paddr); u32 OSCachedToPhysical(void* caddr); @@ -242,8 +224,6 @@ u32 OSUncachedToPhysical(void* ucaddr); void* OSCachedToUncached(void* caddr); void* OSUncachedToCached(void* ucaddr); -#endif // TARGET_PC - #if !DEBUG && !defined(TARGET_PC) #define OSPhysicalToCached(paddr) ((void*) ((u32)(OS_BASE_CACHED + (u32)(paddr)))) #define OSPhysicalToUncached(paddr) ((void*) ((u32)(OS_BASE_UNCACHED + (u32)(paddr)))) @@ -285,6 +265,7 @@ extern int __OSInIPL; // This is dumb but we dont have a Metrowerks way to do variadic macros in the macro to make this done in a not scrubby way. #define ASSERTMSG1LINE(line, cond, msg, arg1) \ ((cond) || (OSPanic(__FILE__, line, msg, arg1), 0)) + #define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) \ ((cond) || (OSPanic(__FILE__, line, msg, arg1, arg2), 0)) @@ -317,6 +298,7 @@ extern int __OSInIPL; #define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) (void)0 #define ASSERTMSGLINEV(line, cond, ...) (void)0 #endif + #define ASSERT(cond) ASSERTLINE(__LINE__, cond) inline s16 __OSf32tos16(__REGISTER f32 inF) { @@ -387,5 +369,4 @@ static inline void OSInitFastCast(void) { #ifdef __cplusplus } #endif - #endif diff --git a/lib/dolphin/AR.cpp b/lib/dolphin/AR.cpp new file mode 100644 index 0000000..3e29f8f --- /dev/null +++ b/lib/dolphin/AR.cpp @@ -0,0 +1,111 @@ +#include +#include "../internal.hpp" +#include "dolphin/os.h" + +static aurora::Module Log("aurora::ar"); + +static u32 AR_StackPointer; +static u32* AR_BlockLength; +static u32 AR_FreeBlocks; +static BOOL AR_init_flag; + +#define ARAM_STACK_START 0x4000; + +// ARAM emulation: allocate a large buffer to simulate the GameCube's Auxiliary RAM. +// ARAM "addresses" are offsets into this buffer. On GameCube, ARAM is 16 MB starting +// at a base address returned by ARInit. We emulate this by malloc'ing a buffer +// and using a simple bump allocator (matching ARAlloc behavior on real hardware). +static u8* sAramBuffer = nullptr; + +// Convert an ARAM "address" (offset) to a real host pointer +static u8* aramToHost(u32 aramAddr) { + if (!sAramBuffer || aramAddr >= aurora::g_config.mem2Size) { + return nullptr; + } + return sAramBuffer + aramAddr; +} + +u32 ARAlloc(u32 length) { + u32 tmp; + + ASSERTMSGLINE(430, !(length & 0x1F), "ARAlloc(): length is not multiple of 32bytes!"); + ASSERTMSGLINE(434, length <= (__AR_Size - __AR_StackPointer), "ARAlloc(): Out of ARAM!"); + ASSERTMSGLINE(435, __AR_FreeBlocks, "ARAlloc(): No more free blocks!"); + + tmp = AR_StackPointer; + AR_StackPointer += length; + *AR_BlockLength = length; + AR_BlockLength += 1; + AR_FreeBlocks -= 1; + return tmp; +} + +u32 ARFree(u32* length) { + AR_BlockLength -= 1; + if (length) { + *length = *AR_BlockLength; + } + AR_StackPointer -= *AR_BlockLength; + AR_FreeBlocks += 1; + return AR_StackPointer; +} + +BOOL ARCheckInit(void) { return AR_init_flag; } + +u32 ARInit(u32* stack_index_addr, u32 num_entries) { + if (aurora::g_config.mem2Size == 0) { + Log.warn("ARInit called but no mem2Size specified in AuroraConfig. ARAM will not be available!"); + return 0; + } + + if (AR_init_flag == TRUE) { + return ARAM_STACK_START; + } + + sAramBuffer = (u8*)calloc(1, aurora::g_config.mem2Size); + if (sAramBuffer) { + Log.debug("Initialized 0x{:X} bytes of ARAM!", aurora::g_config.mem2Size); + } else { + Log.fatal("Failed to allocate ARAM!"); + } + + AR_StackPointer = ARAM_STACK_START; + AR_FreeBlocks = num_entries; + AR_BlockLength = stack_index_addr; + + AR_init_flag = TRUE; + return AR_StackPointer; +} + +u32 ARGetSize(void) { return aurora::g_config.mem2Size; } + +#pragma mark ARQ +void ARQPostRequest(ARQRequest* request, u32 owner, u32 type, u32 priority, uintptr_t source, uintptr_t dest, + u32 length, ARQCallback callback) { + // Emulate ARAM DMA transfers using memcpy. + // type 0 = MRAM -> ARAM, type 1 = ARAM -> MRAM + if (type == ARAM_DIR_MRAM_TO_ARAM) { + // Main RAM -> ARAM: source is a host pointer (cast to u32), dest is an ARAM offset + u8* hostSrc = (u8*)(uintptr_t)source; + u8* aramDst = aramToHost(dest); + if (aramDst && hostSrc) { + memcpy(aramDst, hostSrc, length); + } + } else { + // ARAM -> Main RAM: source is an ARAM offset, dest is a host pointer (cast to u32) + u8* aramSrc = aramToHost(source); + u8* hostDst = (u8*)(uintptr_t)dest; + if (aramSrc && hostDst) { + memcpy(hostDst, aramSrc, length); + } + } + + // Immediately invoke the callback (synchronous on PC, no DMA latency) + if (callback) { + callback((uintptr_t)request); + } +} + +void ARQInit() { + // Nothing to do on PC - ARAM is initialized in ARInit +} \ No newline at end of file diff --git a/lib/dolphin/os/OSAddress.cpp b/lib/dolphin/os/OSAddress.cpp new file mode 100644 index 0000000..8ca1b4a --- /dev/null +++ b/lib/dolphin/os/OSAddress.cpp @@ -0,0 +1,41 @@ +#include "internal.hpp" +#include + +#include + +#if NDEBUG +#undef OSPhysicalToCached +#undef OSPhysicalToUncached +#undef OSCachedToPhysical +#undef OSUncachedToPhysical +#undef OSCachedToUncached +#undef OSUncachedToCached +#endif + +void* OSPhysicalToCached(u32 paddr) { + assert (paddr <= aurora::g_config.mem1Size); + return POINTER_ADD(MEM1Start, paddr); +} + +void* OSPhysicalToUncached(u32 paddr) { + return OSPhysicalToCached(paddr); +} + +u32 OSCachedToPhysical(void* caddr) { + assert (caddr >= MEM1Start && caddr <= MEM1End); + + return (reinterpret_cast(caddr) - reinterpret_cast(MEM1Start)); +} + +u32 OSUncachedToPhysical(void* ucaddr) { + return OSCachedToPhysical(ucaddr); +} + +void* OSCachedToUncached(void* caddr) { + return caddr; +} + +void* OSUncachedToCached(void* ucaddr) { + return ucaddr; +} + diff --git a/lib/dolphin/os/OSArena.cpp b/lib/dolphin/os/OSArena.cpp new file mode 100644 index 0000000..5eeb861 --- /dev/null +++ b/lib/dolphin/os/OSArena.cpp @@ -0,0 +1,58 @@ +#include + +#include "internal.hpp" + +#include + +#define ROUND64(n, a) (((u64)(n) + (a)-1) & ~(u64)((a)-1)) +#define TRUNC64(n, a) (((u64)(n)) & ~(u64)((a)-1)) + +static void* ArenaLow; +static void* ArenaHigh; + +void* OSGetArenaHi() { + return ArenaHigh; +} + +void* OSGetArenaLo() { + return ArenaLow; +} + +void OSSetArenaHi(void* newHi) { + assert(newHi <= MEM1End && newHi >= MEM1Start); + ArenaHigh = newHi; +} + +void OSSetArenaLo(void* newLo) { + assert(newLo <= MEM1End && newLo >= MEM1Start); + ArenaLow = newLo; +} + +void* OSAllocFromArenaLo(const u32 size, const u32 align) { + void* ptr = OSGetArenaLo(); + auto arenaLo = static_cast(ptr = reinterpret_cast(ROUND64(ptr, align))); + arenaLo += size; + arenaLo = reinterpret_cast(ROUND64(arenaLo, align)); + OSSetArenaLo(arenaLo); + return ptr; +} + +void* OSAllocFromArenaHi(const u32 size, const u32 align) { + void* ptr; + + auto arenaHi = static_cast(OSGetArenaHi()); + arenaHi = reinterpret_cast(TRUNC64(arenaHi, align)); + arenaHi -= size; + arenaHi = static_cast(ptr = reinterpret_cast(TRUNC64(arenaHi, align))); + OSSetArenaHi(arenaHi); + return ptr; +} + +void AuroraInitArena() { + if (MEM1Start == nullptr) { + return; + } + + OSSetArenaLo(static_cast(MEM1Start) + ARENA_START_OFFSET); + OSSetArenaHi(MEM1End); +} diff --git a/lib/dolphin/os/OSBootInfo.cpp b/lib/dolphin/os/OSBootInfo.cpp new file mode 100644 index 0000000..e13af46 --- /dev/null +++ b/lib/dolphin/os/OSBootInfo.cpp @@ -0,0 +1,12 @@ +#include "internal.hpp" +#include + +void AuroraFillBootInfo() { + if (OSBaseAddress == 0) { + return; + } + + const auto info = static_cast(OSPhysicalToCached(0)); + + info->memorySize = aurora::g_config.mem1Size; +} diff --git a/lib/dolphin/os/OSInit.cpp b/lib/dolphin/os/OSInit.cpp new file mode 100644 index 0000000..361dd32 --- /dev/null +++ b/lib/dolphin/os/OSInit.cpp @@ -0,0 +1,18 @@ +#include "internal.hpp" + +#include + +static bool AlreadyInitialized; + +void OSInit() { + if (AlreadyInitialized) { + return; + } + + AlreadyInitialized = true; + + AuroraOSInitMemory(); + AuroraFillBootInfo(); + AuroraInitClock(); + AuroraInitArena(); +} diff --git a/lib/dolphin/os/OSMemory.cpp b/lib/dolphin/os/OSMemory.cpp new file mode 100644 index 0000000..75a40ab --- /dev/null +++ b/lib/dolphin/os/OSMemory.cpp @@ -0,0 +1,149 @@ +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#endif + +#include "fmt/base.h" + +#include + +#include "internal.hpp" +#include +#include "dolphin/types.h" + +#if !NDEBUG && (INTPTR_MAX > INT32_MAX) +#define GUARD_MEMORY 1 +#endif + +uintptr_t OSBaseAddress = 0; + +void* MEM1Start; +void* MEM1End; + +static void GuardGCMemory(); +static void* AllocMEM1(u32 size); + +void AuroraOSInitMemory() { + GuardGCMemory(); + + if (aurora::g_config.mem1Size > 0) { + MEM1Start = AllocMEM1(aurora::g_config.mem1Size); + MEM1End = reinterpret_cast(reinterpret_cast(MEM1Start) + aurora::g_config.mem1Size); + OSBaseAddress = reinterpret_cast(MEM1Start); + } +} + +#if GUARD_MEMORY +static uintptr_t GetAllocationGranularity() { +#if _WIN32 + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + + return sysInfo.dwAllocationGranularity; +#else + // TODO: posix impl + return 0; +#endif +} + +static void TryGuardRegion(const uintptr_t start, const uintptr_t end, char const* const name) { + assert(start != 0); + +#if _WIN32 + const auto addr = VirtualAlloc( + reinterpret_cast(start), + end - start, + MEM_RESERVE, + PAGE_NOACCESS); + + if (addr == nullptr) { + Log.debug("Unable to guard memory region: {}", name); + } else { + assert(addr == reinterpret_cast(start)); + Log.debug("Successfully guarded memory range: {:08X}-{:08X} ({})", start, end, name); + } +#else + // TODO: posix impl +#endif +} + +static void GuardGCMemory() { + // Reserve the normal GC/Wii memory map so accesses are 100% guaranteed to fail. + // https://www.gc-forever.com/yagcd/chap5.html#sec5.11 + // https://wiibrew.org/wiki/Memory_map + + // We can't quite map at address 0 (for good reasons) but we *can* map at the next granularity over! + TryGuardRegion(0x00000000 + GetAllocationGranularity(), 0x017fffff, "MEM1 Physical"); + TryGuardRegion(0x80000000, 0x817fffff, "MEM1 Logical (cached)"); + TryGuardRegion(0xC0000000, 0xC17fffff, "MEM1 Logical (uncached)"); + TryGuardRegion(0x10000000, 0x13FFFFFF, "MEM2 Physical"); + TryGuardRegion(0x90000000, 0x93FFFFFF, "MEM2 Logical (cached)"); + TryGuardRegion(0xD0000000, 0xD3FFFFFF, "MEM2 Logical (uncached)"); + TryGuardRegion(0x08000000, 0x08300000, "EFB Physical"); + TryGuardRegion(0xC8000000, 0xC8300000, "EFB Logical"); + TryGuardRegion(0x0D000000, 0x0D008000, "Hollywood HW registers Physical"); + TryGuardRegion(0xCD000000, 0xCD008000, "Hollywood HW registers Logical"); + TryGuardRegion(0x0C000000, 0x0C008020, "Broadway/GC HW registers Physical"); + TryGuardRegion(0xCC000000, 0xCC008020, "Broadway/GC HW registers Logical"); + TryGuardRegion(0xe0000000, 0xe0003fff, "GC L2 cache"); + TryGuardRegion(0xfff00000, 0xffffffff, "GC IPL"); +} +#else +static void GuardGCMemory() { } +#endif + +#if _WIN64 && !NDEBUG +static void* AllocMEM1(u32 size) { + // Allocate an entire 32-bit's worth of memory and allocate the real MEM1 in that. + // This way, if a 64-bit pointer gets truncated to 32-bit, it will still fall in our guard pages. + + void* bulkChunk = VirtualAlloc( + nullptr, + 8ll * 1024 * 1024 * 1024, + MEM_RESERVE, + PAGE_NOACCESS); + + if (bulkChunk == nullptr) { + DWORD err = GetLastError(); + fmt::memory_buffer msg; + fmt::format_system_error( + msg, + static_cast(err), + "Failed to allocate bulk chunk for MEM1"); + Log.fatal("{}", fmt::to_string(msg)); + } + + uintptr_t memSpace = (reinterpret_cast(bulkChunk) | 0xFFFFFFFF) + 1; + void* mem1Address = reinterpret_cast(memSpace + 0x80000000); + + Log.debug("Reserved memory map at {:016X}-{:016X}", memSpace, memSpace + 0xFFFFFFFF); + Log.debug( + "MEM1 at {:016X}-{:016X}", + reinterpret_cast(mem1Address), + reinterpret_cast(mem1Address) + size); + + void* result = VirtualAlloc(mem1Address, size, MEM_COMMIT, PAGE_READWRITE); + if (result == nullptr) { + DWORD err = GetLastError(); + fmt::memory_buffer msg; + fmt::format_system_error( + msg, + static_cast(err), + "Failed to commit memory for MEM1"); + Log.fatal("{}", fmt::to_string(msg)); + } + + assert(result == mem1Address); + return result; +} +#else +static void* AllocMEM1(u32 size) { + return calloc(1, size); +} +#endif + +u32 OSGetPhysicalMemSize() { + const auto info = static_cast(OSPhysicalToCached(0)); + return info->memorySize; +} \ No newline at end of file diff --git a/lib/dolphin/os/OSReport.cpp b/lib/dolphin/os/OSReport.cpp new file mode 100644 index 0000000..9cd7e3b --- /dev/null +++ b/lib/dolphin/os/OSReport.cpp @@ -0,0 +1,41 @@ +#include +#include + +#include "fmt/base.h" +#include "fmt/printf.h" + +#include "../../logging.hpp" + +#include + +static aurora::Module reporter("aurora::os::report"); + +void OSReport(const char* msg, ...) { + va_list args; + va_start(args, msg); + OSVReport(msg, args); + va_end(args); +} + +static std::string FormatToString(const char* msg, va_list list) { + int ret = vsnprintf(nullptr, 0, msg, list); + std::string buf(ret, '\0'); + vsnprintf(buf.data(), buf.size(), msg, list); + return buf; +} + +void OSVReport(const char* msg, va_list list) { + reporter.info("{}", FormatToString(msg, list)); +} + +void OSPanic(const char* file, int line, const char* msg, ...) { + va_list args; + va_start(args, msg); + reporter.fatal("PANIC {}:{}: {}", file, line, FormatToString(msg, args)); + va_end(args); +} + +void OSFatal(GXColor fg, GXColor bg, const char* msg) { + reporter.fatal("{}", msg); +} + diff --git a/lib/dolphin/os/OSTime.cpp b/lib/dolphin/os/OSTime.cpp new file mode 100644 index 0000000..ef1a446 --- /dev/null +++ b/lib/dolphin/os/OSTime.cpp @@ -0,0 +1,25 @@ +#include + +#include "internal.hpp" +#include + +namespace chrono = std::chrono; +using TickDuration = chrono::duration>; + +OSTick OSGetTick() { + return OSGetTime() & 0xFFFFFFFF; +} + +OSTime OSGetTime() { + auto clockTime = chrono::steady_clock::now().time_since_epoch(); + auto ticksTotal = chrono::duration_cast(clockTime); + return ticksTotal.count(); +} + +void AuroraInitClock() { + if (OSBaseAddress == 0) { + return; + } + + __OSBusClock = OS_TIMER_CLOCK * OS_TIMER_CLOCK_DIVIDER; +} diff --git a/lib/dolphin/os/internal.hpp b/lib/dolphin/os/internal.hpp new file mode 100644 index 0000000..b4311ea --- /dev/null +++ b/lib/dolphin/os/internal.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "../../internal.hpp" +#include + +static aurora::Module Log("aurora::os"); + +constexpr uintptr_t ARENA_START_OFFSET = 0x4000; + +extern void* MEM1Start; +extern void* MEM1End; + +void AuroraOSInitMemory(); +void AuroraFillBootInfo(); +void AuroraInitClock(); +void AuroraInitArena(); diff --git a/lib/internal.hpp b/lib/internal.hpp index 162c16b..4360a6c 100644 --- a/lib/internal.hpp +++ b/lib/internal.hpp @@ -67,6 +67,9 @@ auto underlying(T value) -> std::underlying_type_t { #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) #endif +#define POINTER_ADD_TYPE(type_, ptr_, offset_) ((type_)((uintptr_t)(ptr_) + (uintptr_t)(offset_))) +#define POINTER_ADD(ptr_, offset_) POINTER_ADD_TYPE(decltype(ptr_), ptr_, offset_) + #if !defined(__has_cpp_attribute) #define __has_cpp_attribute(name) 0 #endif @@ -95,6 +98,8 @@ auto underlying(T value) -> std::underlying_type_t { if (!(cond)) \ UNLIKELY { Log.warn(msg, ##__VA_ARGS__); } +#define UNIMPLEMENTED() FATAL("UNIMPLEMENTED: {}", __FUNCTION__) + namespace aurora { extern AuroraConfig g_config;