You've already forked aurora
mirror of
https://github.com/CraftyBoss/aurora.git
synced 2026-07-14 05:07:24 -07:00
OS functions start (#16)
* OS memory start OSInit() MEM1 size configurable via AuroraConfiguration Fancy guard pages (who knows if it'll be useful) * OSGetTime() and OSGetTick() * Fix OSPhysicalToCached etc for 64-bit pointers * Specify memory size in OS boot info Used by TP at least * Fix MEM1Start/MEM1End definition oops * Implement some OS arena functions * DEBUG -> NDEBUG * Implement memory translation functions I decided to remove the macros from the header given they're very unlikely to matter perf wise and it reduces code duplication. There's no distinction between cached and uncached. Physical is relative to MEM1. * Fix symbol mismatches from forgetting to include the header * Implement OSReport and similar logging functions * Fix OSBaseAddress Ugh * Implement OSGetPhysicalMemSize * Fix usage of static for global variables * Remove ../ prefixes from OS CMake file CLion did this * Remaining headers needed for TP to build * Rider's "Unversioned Files" will keep trolling me * Remove TP-specific OSReport functions * Hardcode OS_BUS_CLOCK in os.h TP has it referenced in an initializer, so relying on MEM1 being initialized is impossible. * Import TP ARAM emulation code * Guard against double OSInit() calls. --------- Co-authored-by: Luke Street <luke@street.dev>
This commit is contained in:
committed by
GitHub
parent
12009bbd7b
commit
e4afaeeeb7
@@ -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 ()
|
||||
|
||||
@@ -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)
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <aurora/event.h>
|
||||
#include <aurora/main.h>
|
||||
#include <dolphin/gx.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.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 {
|
||||
|
||||
+15
-34
@@ -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<void*>(static_cast<uintptr_t>(paddr));
|
||||
}
|
||||
static inline void* OSPhysicalToUncached(u32 paddr) {
|
||||
return reinterpret_cast<void*>(static_cast<uintptr_t>(paddr));
|
||||
}
|
||||
static inline u32 OSCachedToPhysical(void* caddr) {
|
||||
return static_cast<u32>(reinterpret_cast<uintptr_t>(caddr));
|
||||
}
|
||||
static inline u32 OSUncachedToPhysical(void* ucaddr) {
|
||||
return static_cast<u32>(reinterpret_cast<uintptr_t>(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
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#include <dolphin/ar.h>
|
||||
#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
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "internal.hpp"
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#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<uintptr_t>(caddr) - reinterpret_cast<uintptr_t>(MEM1Start));
|
||||
}
|
||||
|
||||
u32 OSUncachedToPhysical(void* ucaddr) {
|
||||
return OSCachedToPhysical(ucaddr);
|
||||
}
|
||||
|
||||
void* OSCachedToUncached(void* caddr) {
|
||||
return caddr;
|
||||
}
|
||||
|
||||
void* OSUncachedToCached(void* ucaddr) {
|
||||
return ucaddr;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <cassert>
|
||||
|
||||
#include "internal.hpp"
|
||||
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#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<u8*>(ptr = reinterpret_cast<void*>(ROUND64(ptr, align)));
|
||||
arenaLo += size;
|
||||
arenaLo = reinterpret_cast<u8*>(ROUND64(arenaLo, align));
|
||||
OSSetArenaLo(arenaLo);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* OSAllocFromArenaHi(const u32 size, const u32 align) {
|
||||
void* ptr;
|
||||
|
||||
auto arenaHi = static_cast<u8*>(OSGetArenaHi());
|
||||
arenaHi = reinterpret_cast<u8*>(TRUNC64(arenaHi, align));
|
||||
arenaHi -= size;
|
||||
arenaHi = static_cast<u8*>(ptr = reinterpret_cast<void*>(TRUNC64(arenaHi, align)));
|
||||
OSSetArenaHi(arenaHi);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void AuroraInitArena() {
|
||||
if (MEM1Start == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
OSSetArenaLo(static_cast<u8*>(MEM1Start) + ARENA_START_OFFSET);
|
||||
OSSetArenaHi(MEM1End);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "internal.hpp"
|
||||
#include <dolphin/os.h>
|
||||
|
||||
void AuroraFillBootInfo() {
|
||||
if (OSBaseAddress == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto info = static_cast<OSBootInfo*>(OSPhysicalToCached(0));
|
||||
|
||||
info->memorySize = aurora::g_config.mem1Size;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "internal.hpp"
|
||||
|
||||
#include <dolphin/os.h>
|
||||
|
||||
static bool AlreadyInitialized;
|
||||
|
||||
void OSInit() {
|
||||
if (AlreadyInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
AlreadyInitialized = true;
|
||||
|
||||
AuroraOSInitMemory();
|
||||
AuroraFillBootInfo();
|
||||
AuroraInitClock();
|
||||
AuroraInitArena();
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "fmt/base.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "internal.hpp"
|
||||
#include <dolphin/os.h>
|
||||
#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<void*>(reinterpret_cast<uintptr_t>(MEM1Start) + aurora::g_config.mem1Size);
|
||||
OSBaseAddress = reinterpret_cast<uintptr_t>(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<LPVOID>(start),
|
||||
end - start,
|
||||
MEM_RESERVE,
|
||||
PAGE_NOACCESS);
|
||||
|
||||
if (addr == nullptr) {
|
||||
Log.debug("Unable to guard memory region: {}", name);
|
||||
} else {
|
||||
assert(addr == reinterpret_cast<LPVOID>(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<int>(err),
|
||||
"Failed to allocate bulk chunk for MEM1");
|
||||
Log.fatal("{}", fmt::to_string(msg));
|
||||
}
|
||||
|
||||
uintptr_t memSpace = (reinterpret_cast<uintptr_t>(bulkChunk) | 0xFFFFFFFF) + 1;
|
||||
void* mem1Address = reinterpret_cast<void*>(memSpace + 0x80000000);
|
||||
|
||||
Log.debug("Reserved memory map at {:016X}-{:016X}", memSpace, memSpace + 0xFFFFFFFF);
|
||||
Log.debug(
|
||||
"MEM1 at {:016X}-{:016X}",
|
||||
reinterpret_cast<uintptr_t>(mem1Address),
|
||||
reinterpret_cast<uintptr_t>(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<int>(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<OSBootInfo*>(OSPhysicalToCached(0));
|
||||
return info->memorySize;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/gx/GXStruct.h>
|
||||
|
||||
#include "fmt/base.h"
|
||||
#include "fmt/printf.h"
|
||||
|
||||
#include "../../logging.hpp"
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <chrono>
|
||||
|
||||
#include "internal.hpp"
|
||||
#include <dolphin/os.h>
|
||||
|
||||
namespace chrono = std::chrono;
|
||||
using TickDuration = chrono::duration<s64, std::ratio<1, OS_TIMER_CLOCK>>;
|
||||
|
||||
OSTick OSGetTick() {
|
||||
return OSGetTime() & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
OSTime OSGetTime() {
|
||||
auto clockTime = chrono::steady_clock::now().time_since_epoch();
|
||||
auto ticksTotal = chrono::duration_cast<TickDuration>(clockTime);
|
||||
return ticksTotal.count();
|
||||
}
|
||||
|
||||
void AuroraInitClock() {
|
||||
if (OSBaseAddress == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
__OSBusClock = OS_TIMER_CLOCK * OS_TIMER_CLOCK_DIVIDER;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../internal.hpp"
|
||||
#include <dolphin/types.h>
|
||||
|
||||
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();
|
||||
@@ -67,6 +67,9 @@ auto underlying(T value) -> std::underlying_type_t<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<T> {
|
||||
if (!(cond)) \
|
||||
UNLIKELY { Log.warn(msg, ##__VA_ARGS__); }
|
||||
|
||||
#define UNIMPLEMENTED() FATAL("UNIMPLEMENTED: {}", __FUNCTION__)
|
||||
|
||||
namespace aurora {
|
||||
extern AuroraConfig g_config;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user