Imported most of dolphin/os

This commit is contained in:
dbalatoni13 2024-11-12 19:16:59 +01:00
parent 023cd90675
commit 970da00ce2
35 changed files with 6591 additions and 131 deletions

View file

@ -2102,6 +2102,8 @@ OSSetErrorHandler = .text:0x800B6FC8; // type:function size:0x1C scope:global
__OSUnhandledException = .text:0x800B6FE4; // type:function size:0x200 scope:global __OSUnhandledException = .text:0x800B6FE4; // type:function size:0x200 scope:global
OSGetFontEncode = .text:0x800B71E4; // type:function size:0x58 OSGetFontEncode = .text:0x800B71E4; // type:function size:0x58
OSDisableInterrupts = .text:0x800B723C; // type:function size:0x14 scope:global OSDisableInterrupts = .text:0x800B723C; // type:function size:0x14 scope:global
__RAS_OSDisableInterrupts_begin = .text:0x800B723C; // type:label scope:global
__RAS_OSDisableInterrupts_end = .text:0x800B724C; // type:label scope:global
OSEnableInterrupts = .text:0x800B7250; // type:function size:0x14 scope:global OSEnableInterrupts = .text:0x800B7250; // type:function size:0x14 scope:global
OSRestoreInterrupts = .text:0x800B7264; // type:function size:0x24 scope:global OSRestoreInterrupts = .text:0x800B7264; // type:function size:0x24 scope:global
__OSSetInterruptHandler = .text:0x800B7288; // type:function size:0x1C scope:global __OSSetInterruptHandler = .text:0x800B7288; // type:function size:0x1C scope:global
@ -4343,7 +4345,25 @@ lbl_8013B60C = .data:0x8013B60C; // type:object size:0x12 scope:local data:strin
lbl_8013B620 = .data:0x8013B620; // type:object size:0xE scope:local data:string lbl_8013B620 = .data:0x8013B620; // type:object size:0xE scope:local data:string
lbl_8013B630 = .data:0x8013B630; // type:object size:0x15 scope:local data:string lbl_8013B630 = .data:0x8013B630; // type:object size:0x15 scope:local data:string
__OSExceptionLocations = .data:0x8013B648; // type:object size:0x3C scope:local __OSExceptionLocations = .data:0x8013B648; // type:object size:0x3C scope:local
lbl_8013B720 = .data:0x8013B720; // type:object size:0x398 lbl_8013B720 = .data:0x8013B720; // type:object size:0x24 scope:local data:string
lbl_8013B744 = .data:0x8013B744; // type:object size:0x37 scope:local data:string
lbl_8013B77C = .data:0x8013B77C; // type:object size:0x28 scope:local data:string
lbl_8013B7A4 = .data:0x8013B7A4; // type:object size:0x4F scope:local data:string
lbl_8013B7F4 = .data:0x8013B7F4; // type:object size:0x3E scope:local data:string
lbl_8013B834 = .data:0x8013B834; // type:object size:0x37 scope:local data:string
lbl_8013B86C = .data:0x8013B86C; // type:object size:0x49 scope:local data:string
lbl_8013B8B8 = .data:0x8013B8B8; // type:object size:0x33 scope:local data:string
lbl_8013B8EC = .data:0x8013B8EC; // type:object size:0x3D scope:local data:string
lbl_8013B92C = .data:0x8013B92C; // type:object size:0x39 scope:local data:string
lbl_8013B968 = .data:0x8013B968; // type:object size:0x45 scope:local data:string
lbl_8013B9B0 = .data:0x8013B9B0; // type:object size:0x5F scope:local data:string
lbl_8013BA10 = .data:0x8013BA10; // type:object size:0x2C scope:local data:string
lbl_8013BA3C = .data:0x8013BA3C; // type:object size:0x12 scope:local data:string
lbl_8013BA50 = .data:0x8013BA50; // type:object size:0x12 scope:local data:string
lbl_8013BA64 = .data:0x8013BA64; // type:object size:0x1A scope:local data:string
lbl_8013BA80 = .data:0x8013BA80; // type:object size:0x13 scope:local data:string
lbl_8013BA94 = .data:0x8013BA94; // type:object size:0x10 scope:local data:string
lbl_8013BAA4 = .data:0x8013BAA4; // type:object size:0xE scope:local data:string
DSPInitCode = .data:0x8013BAB8; // type:object size:0x80 scope:local DSPInitCode = .data:0x8013BAB8; // type:object size:0x80 scope:local
@69 = .data:0x8013BB38; // type:object size:0x29 scope:local data:string @69 = .data:0x8013BB38; // type:object size:0x29 scope:local data:string
lbl_8013BB64 = .data:0x8013BB64; // type:object size:0x18 scope:local data:string lbl_8013BB64 = .data:0x8013BB64; // type:object size:0x18 scope:local data:string
@ -4360,7 +4380,8 @@ lbl_8013BD00 = .data:0x8013BD00; // type:object size:0x19 scope:local data:strin
lbl_8013BD1C = .data:0x8013BD1C; // type:object size:0x16 scope:local data:string lbl_8013BD1C = .data:0x8013BD1C; // type:object size:0x16 scope:local data:string
lbl_8013BD34 = .data:0x8013BD34; // type:object size:0x2E scope:local data:string lbl_8013BD34 = .data:0x8013BD34; // type:object size:0x2E scope:local data:string
lbl_8013BD68 = .data:0x8013BD68; // type:object size:0x44 scope:local data:string lbl_8013BD68 = .data:0x8013BD68; // type:object size:0x44 scope:local data:string
lbl_8013BDAC = .data:0x8013BDAC; // type:object size:0x5F scope:local data:string lbl_8013BDAC = .data:0x8013BDAC; // type:object size:0x30 scope:local data:string
lbl_8013BDDC = .data:0x8013BDDC; // type:object size:0x2F scope:local data:string
lbl_8013BE0C = .data:0x8013BE0C; // type:object size:0x2F scope:local data:string lbl_8013BE0C = .data:0x8013BE0C; // type:object size:0x2F scope:local data:string
lbl_8013BE3C = .data:0x8013BE3C; // type:object size:0x11 scope:local data:string lbl_8013BE3C = .data:0x8013BE3C; // type:object size:0x11 scope:local data:string
lbl_8013BE50 = .data:0x8013BE50; // type:object size:0x21 scope:local data:string lbl_8013BE50 = .data:0x8013BE50; // type:object size:0x21 scope:local data:string
@ -4370,14 +4391,33 @@ lbl_8013BEA4 = .data:0x8013BEA4; // type:object size:0x12 scope:local data:strin
lbl_8013BEB8 = .data:0x8013BEB8; // type:object size:0x1D scope:local data:string lbl_8013BEB8 = .data:0x8013BEB8; // type:object size:0x1D scope:local data:string
lbl_8013BED8 = .data:0x8013BED8; // type:object size:0x26 scope:local data:string lbl_8013BED8 = .data:0x8013BED8; // type:object size:0x26 scope:local data:string
lbl_8013BF00 = .data:0x8013BF00; // type:object size:0x1C scope:local data:string lbl_8013BF00 = .data:0x8013BF00; // type:object size:0x1C scope:local data:string
@74 = .data:0x8013BF1C; // type:object size:0x23 scope:local data:string @76 = .data:0x8013BF1C; // type:object size:0x23 scope:local data:string
@10 = .data:0x8013BF40; // type:object size:0x16 scope:local data:string @10 = .data:0x8013BF40; // type:object size:0x16 scope:local data:string
@43 = .data:0x8013C21C; // type:object size:0x40 scope:local lbl_8013BF58 = .data:0x8013BF58; // type:object size:0x26 scope:local data:string
lbl_8013BF80 = .data:0x8013BF80; // type:object size:0x1C scope:local data:string
lbl_8013BF9C = .data:0x8013BF9C; // type:object size:0x1D scope:local data:string
lbl_8013BFBC = .data:0x8013BFBC; // type:object size:0x17 scope:local data:string
lbl_8013BFD4 = .data:0x8013BFD4; // type:object size:0x31 scope:local data:string
lbl_8013C008 = .data:0x8013C008; // type:object size:0x10 scope:local data:string
lbl_8013C018 = .data:0x8013C018; // type:object size:0x60 scope:local data:string
lbl_8013C078 = .data:0x8013C078; // type:object size:0x4C scope:local data:string
lbl_8013C0C4 = .data:0x8013C0C4; // type:object size:0x62 scope:local data:string
lbl_8013C128 = .data:0x8013C128; // type:object size:0x60 scope:local data:string
lbl_8013C188 = .data:0x8013C188; // type:object size:0x1F scope:local data:string
lbl_8013C1A8 = .data:0x8013C1A8; // type:object size:0x1F scope:local data:string
lbl_8013C1C8 = .data:0x8013C1C8; // type:object size:0x1B scope:local data:string
lbl_8013C1E4 = .data:0x8013C1E4; // type:object size:0x35 scope:local data:string
@87 = .data:0x8013C21C; // type:object size:0x40 scope:local
InterruptPrioTable = .data:0x8013C260; // type:object size:0x2C scope:local data:4byte InterruptPrioTable = .data:0x8013C260; // type:object size:0x2C scope:local data:4byte
lbl_8013C290 = .data:0x8013C290; // type:object size:0x28 lbl_8013C290 = .data:0x8013C290; // type:object size:0x25 scope:local data:string
lbl_8013C2B8 = .data:0x8013C2B8; // type:object size:0x28 lbl_8013C2B8 = .data:0x8013C2B8; // type:object size:0x27 scope:local data:string
ResetFunctionInfo = .data:0x8013C2E0; // type:object size:0x10 scope:local ResetFunctionInfo = .data:0x8013C2E0; // type:object size:0x10 scope:local
lbl_8013C2F0 = .data:0x8013C2F0; // type:object size:0x78 lbl_8013C2F0 = .data:0x8013C2F0; // type:object size:0x12 scope:local data:string
lbl_8013C304 = .data:0x8013C304; // type:object size:0x11 scope:local data:string
lbl_8013C318 = .data:0x8013C318; // type:object size:0xD scope:local data:string
lbl_8013C328 = .data:0x8013C328; // type:object size:0x11 scope:local data:string
lbl_8013C33C = .data:0x8013C33C; // type:object size:0x11 scope:local data:string
lbl_8013C350 = .data:0x8013C350; // type:object size:0x11 scope:local data:string
YearDays = .data:0x8013C368; // type:object size:0x30 scope:local YearDays = .data:0x8013C368; // type:object size:0x30 scope:local
LeapYearDays = .data:0x8013C398; // type:object size:0x30 scope:local LeapYearDays = .data:0x8013C398; // type:object size:0x30 scope:local
lbl_8013C3C8 = .data:0x8013C3C8; // type:object size:0x18 scope:local data:string lbl_8013C3C8 = .data:0x8013C3C8; // type:object size:0x18 scope:local data:string

View file

@ -458,30 +458,30 @@ config.libs = [
DolphinLib( DolphinLib(
"os", "os",
[ [
Object(NonMatching, "dolphin/os/OS.c"), Object(Matching, "dolphin/os/OS.c"),
Object(NonMatching, "dolphin/os/OSAlarm.c"), Object(Matching, "dolphin/os/OSAlarm.c"),
Object(NonMatching, "dolphin/os/OSAlloc.c"), Object(NonMatching, "dolphin/os/OSAlloc.c"),
Object(NonMatching, "dolphin/os/OSArena.c"), Object(Matching, "dolphin/os/OSArena.c"),
Object(NonMatching, "dolphin/os/OSAudioSystem.c"), Object(Matching, "dolphin/os/OSAudioSystem.c"),
Object(NonMatching, "dolphin/os/OSCache.c"), Object(Matching, "dolphin/os/OSCache.c"),
Object(NonMatching, "dolphin/os/OSContext.c"), Object(Matching, "dolphin/os/OSContext.c"),
Object(NonMatching, "dolphin/os/OSError.c"), Object(Matching, "dolphin/os/OSError.c"),
Object(NonMatching, "dolphin/os/OSFont.c"), Object(Matching, "dolphin/os/OSFont.c"),
Object(NonMatching, "dolphin/os/OSInterrupt.c"), Object(Matching, "dolphin/os/OSInterrupt.c"),
Object(NonMatching, "dolphin/os/OSLink.c"), Object(Matching, "dolphin/os/OSLink.c"),
Object(NonMatching, "dolphin/os/OSMessage.c"), Object(Matching, "dolphin/os/OSMessage.c"),
Object(NonMatching, "dolphin/os/OSMemory.c"), Object(Matching, "dolphin/os/OSMemory.c"),
Object(NonMatching, "dolphin/os/OSMutex.c"), Object(Matching, "dolphin/os/OSMutex.c"),
Object(NonMatching, "dolphin/os/OSReboot.c"), Object(NonMatching, "dolphin/os/OSReboot.c"),
Object(NonMatching, "dolphin/os/OSReset.c"), Object(Matching, "dolphin/os/OSReset.c"),
Object(NonMatching, "dolphin/os/OSResetSW.c"), Object(Matching, "dolphin/os/OSResetSW.c"),
Object(NonMatching, "dolphin/os/OSRtc.c"), Object(Matching, "dolphin/os/OSRtc.c"),
Object(NonMatching, "dolphin/os/OSStopwatch.c"), Object(Matching, "dolphin/os/OSStopwatch.c"),
Object(NonMatching, "dolphin/os/OSSync.c"), Object(Matching, "dolphin/os/OSSync.c"),
Object(NonMatching, "dolphin/os/OSThread.c"), Object(Matching, "dolphin/os/OSThread.c"),
Object(NonMatching, "dolphin/os/OSTime.c"), Object(Matching, "dolphin/os/OSTime.c"),
Object(NonMatching, "dolphin/os/__start.c"), Object(Matching, "dolphin/os/__start.c"),
Object(NonMatching, "dolphin/os/__ppc_eabi_init.c"), Object(Matching, "dolphin/os/__ppc_eabi_init.c"),
], ],
), ),
DolphinLib( DolphinLib(

View file

@ -0,0 +1,79 @@
#ifndef __PPC_EABI_LINKER
#define __PPC_EABI_LINKER
#ifdef __MWERKS__
#define DECL_SECTION(name) __declspec(section name)
#else
#define DECL_SECTION(name)
#endif
DECL_SECTION(".init") extern char _stack_addr[];
DECL_SECTION(".init") extern char _stack_end[];
DECL_SECTION(".init") extern char _heap_addr[];
DECL_SECTION(".init") extern char _heap_end[];
DECL_SECTION(".init") extern const char _fextabindex_rom[];
DECL_SECTION(".init") extern char _fextabindex[];
DECL_SECTION(".init") extern char _eextabindex[];
DECL_SECTION(".init") extern char _SDA_BASE_[];
DECL_SECTION(".init") extern char _SDA2_BASE_[];
typedef struct __rom_copy_info {
char* rom;
char* addr;
unsigned int size;
} __rom_copy_info;
DECL_SECTION(".init") extern __rom_copy_info _rom_copy_info[];
typedef struct __bss_init_info {
char* addr;
unsigned int size;
} __bss_init_info;
DECL_SECTION(".init") extern __bss_init_info _bss_init_info[];
typedef struct __eti_init_info {
void* eti_start;
void* eti_end;
void* code_start;
unsigned long code_size;
} __eti_init_info;
DECL_SECTION(".init") extern __eti_init_info _eti_init_info[];
DECL_SECTION(".init") extern const char _f_init_rom[];
DECL_SECTION(".init") extern char _f_init[];
DECL_SECTION(".init") extern char _e_init[];
DECL_SECTION(".init") extern const char _f_text_rom[];
DECL_SECTION(".init") extern char _f_text[];
DECL_SECTION(".init") extern char _e_text[];
DECL_SECTION(".init") extern const char _f_rodata_rom[];
DECL_SECTION(".init") extern char _f_rodata[];
DECL_SECTION(".init") extern char _e_rodata[];
DECL_SECTION(".init") extern const char _fextab_rom[];
DECL_SECTION(".init") extern char _fextab[];
DECL_SECTION(".init") extern char _eextab[];
DECL_SECTION(".init") extern const char _f_data_rom[];
DECL_SECTION(".init") extern char _f_data[];
DECL_SECTION(".init") extern char _e_data[];
DECL_SECTION(".init") extern char _f_bss[];
DECL_SECTION(".init") extern char _e_bss[];
DECL_SECTION(".init") extern const char _f_sdata_rom[];
DECL_SECTION(".init") extern char _f_sdata[];
DECL_SECTION(".init") extern char _e_sdata[];
DECL_SECTION(".init") extern char _f_sbss[];
DECL_SECTION(".init") extern char _e_sbss[];
DECL_SECTION(".init") extern const char _f_sdata2_rom[];
DECL_SECTION(".init") extern char _f_sdata2[];
DECL_SECTION(".init") extern char _e_sdata2[];
DECL_SECTION(".init") extern char _f_sbss2[];
DECL_SECTION(".init") extern char _e_sbss2[];
DECL_SECTION(".init") extern const char _f_PPC_EMB_sdata0_rom[];
DECL_SECTION(".init") extern char _f_PPC_EMB_sdata0[];
DECL_SECTION(".init") extern char _e_PPC_EMB_sdata0[];
DECL_SECTION(".init") extern char _f_PPC_EMB_sbss0[];
DECL_SECTION(".init") extern char _e_PPC_EMB_sbss0[];
#endif // __PPC_EABI_LINKER

View file

@ -4,30 +4,33 @@
#include <types.h> #include <types.h>
typedef struct OSSram { typedef struct OSSram {
u16 checkSum; u16 checkSum;
u16 checkSumInv; u16 checkSumInv;
u32 ead0; u32 ead0;
u32 ead1; u32 ead1;
u32 counterBias; u32 counterBias;
s8 displayOffsetH; s8 displayOffsetH;
u8 ntd; u8 ntd;
u8 language; u8 language;
u8 flags; u8 flags;
} OSSram; } OSSram;
typedef struct OSSramEx { typedef struct OSSramEx {
u8 flashID[2][12]; u8 flashID[2][12];
u32 wirelessKeyboardID; u32 wirelessKeyboardID;
u16 wirelessPadID[4]; u16 wirelessPadID[4];
u8 dvdErrorCode; u8 dvdErrorCode;
u8 _padding0; u8 _padding0;
u8 flashIDCheckSum[2]; u8 flashIDCheckSum[2];
u16 gbs; u16 gbs;
u8 _padding1[2]; u8 _padding1[2];
} OSSramEx; } OSSramEx;
OSSram* __OSLockSram(); void __OSInitSram();
OSSramEx* __OSLockSramEx(); OSSram *__OSLockSram();
BOOL __OSSyncSram();
BOOL __OSUnlockSram(BOOL commit);
OSSramEx *__OSLockSramEx();
void OSSetWirelessID(s32 chan, u16 id); void OSSetWirelessID(s32 chan, u16 id);
u16 OSGetWirelessID(s32 chan); u16 OSGetWirelessID(s32 chan);

View file

@ -23,26 +23,26 @@ extern "C" {
#endif #endif
typedef s64 OSTime; typedef s64 OSTime;
typedef u32 OSTick; typedef u32 OSTick;
u32 __OSBusClock AT_ADDRESS(OS_BASE_CACHED | 0x00F8); // sync with OSLoMem.h u32 __OSBusClock AT_ADDRESS(OS_BASE_CACHED | 0x00F8); // sync with OSLoMem.h
u32 __OSCoreClock AT_ADDRESS(OS_BASE_CACHED | 0x00FC); // sync with OSLoMem.h u32 __OSCoreClock AT_ADDRESS(OS_BASE_CACHED | 0x00FC); // sync with OSLoMem.h
#define OS_BUS_CLOCK (u32)__OSBusClock #define OS_BUS_CLOCK (u32) __OSBusClock
#define OS_CORE_CLOCK __OSCoreClock #define OS_CORE_CLOCK __OSCoreClock
#define OS_TIMER_CLOCK (OS_BUS_CLOCK / 4) #define OS_TIMER_CLOCK (OS_BUS_CLOCK / 4)
#ifndef _DEBUG #ifndef _DEBUG
#define OSPhysicalToCached(paddr) ((void*)((u32)(paddr) + OS_BASE_CACHED)) #define OSPhysicalToCached(paddr) ((void *)((u32)(paddr) + OS_BASE_CACHED))
#define OSPhysicalToUncached(paddr) ((void*)((u32)(paddr) + OS_BASE_UNCACHED)) #define OSPhysicalToUncached(paddr) ((void *)((u32)(paddr) + OS_BASE_UNCACHED))
#define OSCachedToPhysical(caddr) ((u32)((u8*)(caddr)-OS_BASE_CACHED)) #define OSCachedToPhysical(caddr) ((u32)((u8 *)(caddr)-OS_BASE_CACHED))
#define OSUncachedToPhysical(ucaddr) ((u32)((u8*)(ucaddr)-OS_BASE_UNCACHED)) #define OSUncachedToPhysical(ucaddr) ((u32)((u8 *)(ucaddr)-OS_BASE_UNCACHED))
#define OSCachedToUncached(caddr) ((void*)((u8*)(caddr) + (OS_BASE_UNCACHED - OS_BASE_CACHED))) #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 OSUncachedToCached(ucaddr) ((void *)((u8 *)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED)))
#else #else
u32 OSPhysicalToCached(void* paddr); u32 OSPhysicalToCached(void *paddr);
u32 OSPhysicalToUncached(void* paddr); u32 OSPhysicalToUncached(void *paddr);
u32 OSCachedToPhysical(void* caddr); u32 OSCachedToPhysical(void *caddr);
u32 OSUncachedToPhysical(void* ucaddr); u32 OSUncachedToPhysical(void *ucaddr);
u32 OSCachedToUncached(void* caddr); u32 OSCachedToUncached(void *caddr);
u32 OSUncachedToCached(void* ucaddr); u32 OSUncachedToCached(void *ucaddr);
#endif #endif
#define OSTicksToCycles(ticks) (((ticks) * ((OS_CORE_CLOCK * 2) / OS_TIMER_CLOCK)) / 2) #define OSTicksToCycles(ticks) (((ticks) * ((OS_CORE_CLOCK * 2) / OS_TIMER_CLOCK)) / 2)
@ -50,7 +50,7 @@ u32 OSUncachedToCached(void* ucaddr);
#define OSTicksToMilliseconds(ticks) ((ticks) / (OS_TIMER_CLOCK / 1000)) #define OSTicksToMilliseconds(ticks) ((ticks) / (OS_TIMER_CLOCK / 1000))
#define OSTicksToMicroseconds(ticks) (((ticks)*8) / (OS_TIMER_CLOCK / 125000)) #define OSTicksToMicroseconds(ticks) (((ticks)*8) / (OS_TIMER_CLOCK / 125000))
#define OSTicksToNanoseconds(ticks) (((ticks)*8000) / (OS_TIMER_CLOCK / 125000)) #define OSTicksToNanoseconds(ticks) (((ticks)*8000) / (OS_TIMER_CLOCK / 125000))
#define OSSecondsToTicks(sec) ((sec)*OS_TIMER_CLOCK) #define OSSecondsToTicks(sec) ((sec)*OS_TIMER_CLOCK)
#define OSMillisecondsToTicks(msec) ((msec) * (OS_TIMER_CLOCK / 1000)) #define OSMillisecondsToTicks(msec) ((msec) * (OS_TIMER_CLOCK / 1000))
#define OSMicrosecondsToTicks(usec) (((usec) * (OS_TIMER_CLOCK / 125000)) / 8) #define OSMicrosecondsToTicks(usec) (((usec) * (OS_TIMER_CLOCK / 125000)) / 8)
#define OSNanosecondsToTicks(nsec) (((nsec) * (OS_TIMER_CLOCK / 125000)) / 8000) #define OSNanosecondsToTicks(nsec) (((nsec) * (OS_TIMER_CLOCK / 125000)) / 8000)
@ -60,52 +60,44 @@ u32 OSUncachedToCached(void* ucaddr);
#define OSRoundUp32B(v) (((u32)(v + 31) & ~31)) #define OSRoundUp32B(v) (((u32)(v + 31) & ~31))
#define OSRoundDown32B(x) (((u32)(x)) & ~31) #define OSRoundDown32B(x) (((u32)(x)) & ~31)
void* OSGetArenaHi(void);
void* OSGetArenaLo(void);
void OSSetArenaHi(void* newHi);
void OSSetArenaLo(void* newLo);
void* OSAllocFromArenaLo(u32 size, u32 align);
void* OSAllocFromArenaHi(u32 size, u32 align);
void OSInit(); void OSInit();
OSTime OSGetTime(); OSTime OSGetTime();
OSTick OSGetTick(); OSTick OSGetTick();
typedef struct OSCalendarTime { typedef struct OSCalendarTime {
int sec; // seconds after the minute [0, 61] int sec; // seconds after the minute [0, 61]
int min; // minutes after the hour [0, 59] int min; // minutes after the hour [0, 59]
int hour; // hours since midnight [0, 23] int hour; // hours since midnight [0, 23]
int mday; // day of the month [1, 31] int mday; // day of the month [1, 31]
int mon; // month since January [0, 11] int mon; // month since January [0, 11]
int year; // years in AD [1, ...] int year; // years in AD [1, ...]
int wday; // days since Sunday [0, 6] int wday; // days since Sunday [0, 6]
int yday; // days since January 1 [0, 365] int yday; // days since January 1 [0, 365]
int msec; // milliseconds after the second [0,999] int msec; // milliseconds after the second [0,999]
int usec; // microseconds after the millisecond [0,999] int usec; // microseconds after the millisecond [0,999]
} OSCalendarTime; } OSCalendarTime;
OSTime OSCalendarTimeToTicks(OSCalendarTime* td); OSTime OSCalendarTimeToTicks(OSCalendarTime *td);
void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td); void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime *td);
typedef struct OSStopwatch { typedef struct OSStopwatch {
char* name; char *name;
OSTime total; OSTime total;
u32 hits; u32 hits;
OSTime min; OSTime min;
OSTime max; OSTime max;
OSTime last; OSTime last;
BOOL running; BOOL running;
} OSStopwatch; } OSStopwatch;
void OSInitStopwatch(OSStopwatch* sw, char* name); void OSInitStopwatch(OSStopwatch *sw, char *name);
void OSStartStopwatch(OSStopwatch* sw); void OSStartStopwatch(OSStopwatch *sw);
void OSStopStopwatch(OSStopwatch* sw); void OSStopStopwatch(OSStopwatch *sw);
OSTime OSCheckStopwatch(OSStopwatch* sw); OSTime OSCheckStopwatch(OSStopwatch *sw);
void OSResetStopwatch(OSStopwatch* sw); void OSResetStopwatch(OSStopwatch *sw);
void OSDumpStopwatch(OSStopwatch* sw); void OSDumpStopwatch(OSStopwatch *sw);
#define OS_CONSOLE_MASK 0xf0000000 #define OS_CONSOLE_MASK 0xf0000000
#define OS_CONSOLE_RETAIL 0x00000000 #define OS_CONSOLE_RETAIL 0x00000000
@ -159,7 +151,7 @@ void OSSetLanguage(u8 language);
u32 OSGetEuRgb60Mode(void); u32 OSGetEuRgb60Mode(void);
void OSSetEuRgb60Mode(u32 on); void OSSetEuRgb60Mode(u32 on);
void OSRegisterVersion(const char* id); void OSRegisterVersion(const char *id);
BOOL OSDisableInterrupts(void); BOOL OSDisableInterrupts(void);
BOOL OSEnableInterrupts(void); BOOL OSEnableInterrupts(void);
@ -174,8 +166,7 @@ BOOL OSRestoreInterrupts(BOOL level);
#endif #endif
#ifndef ASSERTMSG #ifndef ASSERTMSG
#if defined(__STDC_VERSION__) && (199901L <= __STDC_VERSION__) || defined(__MWERKS__) || \ #if defined(__STDC_VERSION__) && (199901L <= __STDC_VERSION__) || defined(__MWERKS__) || defined(__SN__)
defined(__SN__)
#define ASSERTMSG(exp, ...) (void)((exp) || (OSPanic(__FILE__, __LINE__, __VA_ARGS__), 0)) #define ASSERTMSG(exp, ...) (void)((exp) || (OSPanic(__FILE__, __LINE__, __VA_ARGS__), 0))
#else #else
#define ASSERTMSG(exp, msg) (void)((exp) || (OSPanic(__FILE__, __LINE__, (msg)), 0)) #define ASSERTMSG(exp, msg) (void)((exp) || (OSPanic(__FILE__, __LINE__, (msg)), 0))
@ -183,23 +174,20 @@ BOOL OSRestoreInterrupts(BOOL level);
#endif #endif
#ifndef ASSERTMSG1 #ifndef ASSERTMSG1
#define ASSERTMSG1(exp, msg, param1) \ #define ASSERTMSG1(exp, msg, param1) (void)((exp) || (OSPanic(__FILE__, __LINE__, (msg), (param1)), 0))
(void)((exp) || (OSPanic(__FILE__, __LINE__, (msg), (param1)), 0))
#endif #endif
#ifndef ASSERTMSG2 #ifndef ASSERTMSG2
#define ASSERTMSG2(exp, msg, param1, param2) \ #define ASSERTMSG2(exp, msg, param1, param2) (void)((exp) || (OSPanic(__FILE__, __LINE__, (msg), (param1), (param2)), 0))
(void)((exp) || (OSPanic(__FILE__, __LINE__, (msg), (param1), (param2)), 0))
#endif #endif
#ifndef ASSERTMSG3 #ifndef ASSERTMSG3
#define ASSERTMSG3(exp, msg, param1, param2, param3) \ #define ASSERTMSG3(exp, msg, param1, param2, param3) (void)((exp) || (OSPanic(__FILE__, __LINE__, (msg), (param1), (param2), (param3)), 0))
(void)((exp) || (OSPanic(__FILE__, __LINE__, (msg), (param1), (param2), (param3)), 0))
#endif #endif
#ifndef ASSERTMSG4 #ifndef ASSERTMSG4
#define ASSERTMSG4(exp, msg, param1, param2, param3, param4) \ #define ASSERTMSG4(exp, msg, param1, param2, param3, param4) \
(void)((exp) || (OSPanic(__FILE__, __LINE__, (msg), (param1), (param2), (param3), (param4)), 0)) (void)((exp) || (OSPanic(__FILE__, __LINE__, (msg), (param1), (param2), (param3), (param4)), 0))
#endif #endif
#else // _DEBUG #else // _DEBUG
@ -209,8 +197,7 @@ BOOL OSRestoreInterrupts(BOOL level);
#endif #endif
#ifndef ASSERTMSG #ifndef ASSERTMSG
#if defined(__STDC_VERSION__) && (199901L <= __STDC_VERSION__) || defined(__MWERKS__) || \ #if defined(__STDC_VERSION__) && (199901L <= __STDC_VERSION__) || defined(__MWERKS__) || defined(__SN__)
defined(__SN__)
#define ASSERTMSG(exp, ...) ((void)0) #define ASSERTMSG(exp, ...) ((void)0)
#else #else
#define ASSERTMSG(exp, msg) ((void)0) #define ASSERTMSG(exp, msg) ((void)0)
@ -232,9 +219,9 @@ BOOL OSRestoreInterrupts(BOOL level);
#endif // _DEBUG #endif // _DEBUG
void OSReport(const char* msg, ...); void OSReport(const char *msg, ...);
void OSPanic(const char* file, int line, const char* msg, ...); void OSPanic(const char *file, int line, const char *msg, ...);
void OSFatal(GXColor fg, GXColor bg, const char* msg); void OSFatal(GXColor fg, GXColor bg, const char *msg);
u32 OSGetPhysicalMemSize(void); u32 OSGetPhysicalMemSize(void);
u32 OSGetConsoleSimulatedMemSize(void); u32 OSGetConsoleSimulatedMemSize(void);
@ -253,6 +240,7 @@ u32 OSGetConsoleSimulatedMemSize(void);
#include <dolphin/os/OSExpansion.h> #include <dolphin/os/OSExpansion.h>
#include <dolphin/os/OSFastCast.h> #include <dolphin/os/OSFastCast.h>
#include <dolphin/os/OSFont.h> #include <dolphin/os/OSFont.h>
#include <dolphin/os/OSIC.h>
#include <dolphin/os/OSInterrupt.h> #include <dolphin/os/OSInterrupt.h>
#include <dolphin/os/OSMemory.h> #include <dolphin/os/OSMemory.h>
#include <dolphin/os/OSMessage.h> #include <dolphin/os/OSMessage.h>

View file

@ -7,19 +7,18 @@
extern "C" { extern "C" {
#endif #endif
typedef int OSHeapHandle; typedef int OSHeapHandle;
typedef void (*OSAllocVisitor)(void* obj, u32 size); typedef void (*OSAllocVisitor)(void *obj, u32 size);
void* OSInitAlloc(void* arenaStart, void* arenaEnd, int maxHeaps); void *OSInitAlloc(void *arenaStart, void *arenaEnd, int maxHeaps);
OSHeapHandle OSCreateHeap(void* start, void* end); OSHeapHandle OSCreateHeap(void *start, void *end);
void OSDestroyHeap(OSHeapHandle heap); void OSDestroyHeap(OSHeapHandle heap);
void OSAddToHeap(OSHeapHandle heap, void* start, void* end); void OSAddToHeap(OSHeapHandle heap, void *start, void *end);
OSHeapHandle OSSetCurrentHeap(OSHeapHandle heap); OSHeapHandle OSSetCurrentHeap(OSHeapHandle heap);
void* OSAllocFromHeap(OSHeapHandle heap, u32 size); void *OSAllocFromHeap(OSHeapHandle heap, u32 size);
void* OSAllocFixed(void** rstart, void** rend); void *OSAllocFixed(void **rstart, void **rend);
void OSFreeToHeap(OSHeapHandle heap, void* ptr); void OSFreeToHeap(OSHeapHandle heap, void *ptr);
long OSCheckHeap(OSHeapHandle heap); long OSCheckHeap(OSHeapHandle heap);
void OSDumpHeap(OSHeapHandle heap); void OSDumpHeap(OSHeapHandle heap);
void *OSAllocFixed(void **rstart, void **rend); u32 OSReferentSize(void *ptr);
u32 OSReferentSize(void* ptr);
void OSVisitAllocated(OSAllocVisitor visitor); void OSVisitAllocated(OSAllocVisitor visitor);
extern volatile OSHeapHandle __OSCurrHeap; extern volatile OSHeapHandle __OSCurrHeap;
#define OSAlloc(size) OSAllocFromHeap(__OSCurrHeap, (size)) #define OSAlloc(size) OSAllocFromHeap(__OSCurrHeap, (size))

View file

@ -158,10 +158,16 @@ typedef struct OSContext {
} OSContext; } OSContext;
u32 OSGetStackPointer(void);
void OSDumpContext(OSContext *context);
u32 OSSaveContext(OSContext* context); u32 OSSaveContext(OSContext* context);
void OSLoadContext(OSContext* context);
void OSClearContext(OSContext* context); void OSClearContext(OSContext* context);
OSContext* OSGetCurrentContext(); OSContext* OSGetCurrentContext();
void OSSetCurrentContext(OSContext* context); void OSSetCurrentContext(OSContext* context);
void OSSaveFPUContext(OSContext *fpuContext);
void OSInitContext(OSContext *context, u32 pc, u32 newsp);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -9,17 +9,44 @@ extern "C" {
#define OS_FONT_ENCODE_ANSI 0u #define OS_FONT_ENCODE_ANSI 0u
#define OS_FONT_ENCODE_SJIS 1u #define OS_FONT_ENCODE_SJIS 1u
#define OS_FONT_ENCODE_UTF8 3u // UTF-8 [RFC 3629] #define OS_FONT_SIZE_ANSI (288 + 131072) // 9 sheets
#define OS_FONT_ENCODE_UTF16 4u // UTF-16BE [RFC 2781] #define OS_FONT_SIZE_SJIS (3840 + 1179648) // 1 sheet
#define OS_FONT_ENCODE_UTF32 5u // UTF-32 #define OS_FONT_ROM_SIZE_ANSI 0x03000
#define OS_FONT_ENCODE_MAX 5u #define OS_FONT_ROM_SIZE_SJIS 0x4D000
#define OS_FONT_ENCODE_VOID 0xffffu
#define OS_FONT_PROPORTIONAL FALSE typedef struct OSFontHeader
#define OS_FONT_FIXED TRUE {
/*0x00*/ u16 fontType;
u16 firstChar;
u16 lastChar;
u16 invalChar;
/*0x08*/ u16 ascent;
u16 descent;
u16 width;
u16 leading;
/*0x10*/ u16 cellWidth;
u16 cellHeight;
/*0x14*/ u32 sheetSize;
/*0x18*/ u16 sheetFormat;
u16 sheetColumn;
u16 sheetRow;
u16 sheetWidth;
/*0x20*/ u16 sheetHeight;
u16 widthTable;
u32 sheetImage;
u32 sheetFullSize;
u8 c0;
u8 c1;
u8 c2;
u8 c3;
} OSFontHeader;
u16 OSGetFontEncode(void); u16 OSGetFontEncode(void);
u16 OSSetFontEncode(u16 encode); BOOL OSInitFont(OSFontHeader *fontData);
u32 OSLoadFont(OSFontHeader *fontData, void *temp);
char *OSGetFontTexture(char *string, void **image, s32 *x, s32 *y, s32 *width);
char *OSGetFontWidth(char *string, s32 *width);
char *OSGetFontTexel(char *string, void *image, s32 pos, s32 stride, s32 *width);
#ifdef __cplusplus #ifdef __cplusplus
} }

20
include/dolphin/os/OSIC.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef _DOLPHIN_OSIC
#define _DOLPHIN_OSIC
#ifdef __cplusplus
extern "C" {
#endif
void ICFlashInvalidate(void);
void ICEnable(void);
void ICDisable(void);
void ICFreeze(void);
void ICUnfreeze(void);
void ICBlockInvalidate(void *addr);
void ICSync(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -105,8 +105,8 @@ BOOL OSUnlink(OSModuleInfo* oldModule);
OSModuleInfo* OSSearchModule(void* ptr, u32* section, u32* offset); OSModuleInfo* OSSearchModule(void* ptr, u32* section, u32* offset);
// debugger notification // debugger notification
void OSNotifyLink(OSModuleInfo* module); void OSNotifyLink(void);
void OSNotifyUnlink(OSModuleInfo* module); void OSNotifyUnlink(void);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -7,10 +7,42 @@
extern "C" { extern "C" {
#endif #endif
#define OFFSET(addr, align) (((u32)(addr) & ((align)-1)))
// OSAudioSystem.c
void __OSInitAudioSystem(void);
void __OSStopAudioSystem(void);
// OSCache.c
void __OSCacheInit(void);
// OSContext.c
void __OSContextInit(void);
// OSMutex.c
void __OSUnlockAllMutex(struct OSThread *thread);
// OSInterrupt.c
extern void __RAS_OSDisableInterrupts_begin(void);
extern void __RAS_OSDisableInterrupts_end(void);
void __OSInterruptInit(void);
void __OSModuleInit(void);
void __OSInitSystemCall(void);
// OSThread.c
void __OSThreadInit(void);
void __OSReschedule(void);
typedef void (*OSExceptionHandler)(__OSException, OSContext*);
OSExceptionHandler __OSSetExceptionHandler(__OSException exception, OSExceptionHandler handler);
__OSExceptionHandler __OSGetExceptionHandler(__OSException exception); __OSExceptionHandler __OSGetExceptionHandler(__OSException exception);
OSTime __OSGetSystemTime(); OSTime __OSGetSystemTime();
OSTime __OSTimeToSystemTime(OSTime); OSTime __OSTimeToSystemTime(OSTime);
// OSReboot
void __OSReboot(u32 resetCode, u32 bootDol);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

645
src/dolphin/os/OS.c Normal file
View file

@ -0,0 +1,645 @@
#include <__ppc_eabi_linker.h>
#include <dolphin/DVDPriv.h>
#include <dolphin/OSRtcPriv.h>
#include <dolphin/PPCArch.h>
#include <dolphin/db.h>
#include <dolphin/exi.h>
#include <dolphin/os.h>
#include <dolphin/os/OSBootInfo.h>
#include <dolphin/os/OSPriv.h>
#include <dolphin/sipriv.h>
extern OSTime __OSGetSystemTime();
extern char _db_stack_end[];
#define OS_BI2_DEBUG_ADDRESS 0x800000F4
#define DEBUGFLAG_ADDR 0x800030E8
#define OS_DEBUG_ADDRESS_2 0x800030E9
#define OS_CURRENTCONTEXT_PADDR 0x00C0
extern char *__OSResetSWInterruptHandler[];
vu16 __OSDeviceCode : (OS_BASE_CACHED | 0x30E6);
static DVDDriveInfo DriveInfo ATTRIBUTE_ALIGN(32);
static DVDCommandBlock DriveBlock;
static OSBootInfo *BootInfo;
static u32 *BI2DebugFlag;
static u32 *BI2DebugFlagHolder;
__declspec(weak) BOOL __OSIsGcam = FALSE;
static f64 ZeroF;
static f32 ZeroPS[2];
static BOOL AreWeInitialized = FALSE;
static __OSExceptionHandler *OSExceptionTable;
OSTime __OSStartTime;
BOOL __OSInIPL;
extern u8 __ArenaHi[];
extern u8 __ArenaLo[];
extern u32 __DVDLongFileNameFlag;
extern u32 __PADSpec;
#define OS_EXCEPTIONTABLE_ADDR 0x3000
#define OS_DBJUMPPOINT_ADDR 0x60
// memory locations for important stuff
#define OS_CACHED_REGION_PREFIX 0x8000
#define OS_BI2_DEBUG_ADDRESS 0x800000F4
#define OS_BI2_DEBUGFLAG_OFFSET 0xC
#define PAD3_BUTTON_ADDR 0x800030E4
#define OS_DVD_DEVICECODE 0x800030E6
#define DEBUGFLAG_ADDR 0x800030E8
#define OS_DEBUG_ADDRESS_2 0x800030E9
#define DB_EXCEPTIONRET_OFFSET 0xC
#define DB_EXCEPTIONDEST_OFFSET 0x8
void OSDefaultExceptionHandler(__OSException exception, OSContext *context);
extern BOOL __DBIsExceptionMarked(__OSException);
static void OSExceptionInit(void);
/* clang-format off */
asm void __OSFPRInit(void)
{
nofralloc
mfmsr r3
ori r3, r3, 0x2000
mtmsr r3
mfspr r3, 0x398
rlwinm. r3, r3, 3, 31, 31
beq SkipPairedSingles
lis r3, ZeroPS@ha
addi r3, r3, ZeroPS@l
psq_l fp0, 0(r3), 0, 0
ps_mr fp1, fp0
ps_mr fp2, fp0
ps_mr fp3, fp0
ps_mr fp4, fp0
ps_mr fp5, fp0
ps_mr fp6, fp0
ps_mr fp7, fp0
ps_mr fp8, fp0
ps_mr fp9, fp0
ps_mr fp10, fp0
ps_mr fp11, fp0
ps_mr fp12, fp0
ps_mr fp13, fp0
ps_mr fp14, fp0
ps_mr fp15, fp0
ps_mr fp16, fp0
ps_mr fp17, fp0
ps_mr fp18, fp0
ps_mr fp19, fp0
ps_mr fp20, fp0
ps_mr fp21, fp0
ps_mr fp22, fp0
ps_mr fp23, fp0
ps_mr fp24, fp0
ps_mr fp25, fp0
ps_mr fp26, fp0
ps_mr fp27, fp0
ps_mr fp28, fp0
ps_mr fp29, fp0
ps_mr fp30, fp0
ps_mr fp31, fp0
SkipPairedSingles:
lfd fp0, ZeroF
fmr fp1, fp0
fmr fp2, fp0
fmr fp3, fp0
fmr fp4, fp0
fmr fp5, fp0
fmr fp6, fp0
fmr fp7, fp0
fmr fp8, fp0
fmr fp9, fp0
fmr fp10, fp0
fmr fp11, fp0
fmr fp12, fp0
fmr fp13, fp0
fmr fp14, fp0
fmr fp15, fp0
fmr fp16, fp0
fmr fp17, fp0
fmr fp18, fp0
fmr fp19, fp0
fmr fp20, fp0
fmr fp21, fp0
fmr fp22, fp0
fmr fp23, fp0
fmr fp24, fp0
fmr fp25, fp0
fmr fp26, fp0
fmr fp27, fp0
fmr fp28, fp0
fmr fp29, fp0
fmr fp30, fp0
fmr fp31, fp0
mtfsf 0xFF, fp0
blr
}
/* clang-format on */
u32 OSGetConsoleType()
{
if (BootInfo == NULL || BootInfo->consoleType == 0) {
return OS_CONSOLE_ARTHUR;
}
return BootInfo->consoleType;
}
void *__OSSavedRegionStart;
void *__OSSavedRegionEnd;
extern u32 BOOT_REGION_START : 0x812FDFF0; //(*(u32 *)0x812fdff0)
extern u32 BOOT_REGION_END : 0x812FDFEC; //(*(u32 *)0x812fdfec)
void ClearArena(void)
{
if ((u32)(OSGetResetCode() + 0x80000000) != 0U) {
__OSSavedRegionStart = 0U;
__OSSavedRegionEnd = 0U;
memset(OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo());
return;
}
__OSSavedRegionStart = (void *)BOOT_REGION_START;
__OSSavedRegionEnd = (void *)BOOT_REGION_END;
if (BOOT_REGION_START == 0U) {
memset(OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo());
return;
}
if ((u32)OSGetArenaLo() < (u32)__OSSavedRegionStart) {
if ((u32)OSGetArenaHi() <= (u32)__OSSavedRegionStart) {
memset((u32)OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo());
return;
}
memset(OSGetArenaLo(), 0U, (u32)__OSSavedRegionStart - (u32)OSGetArenaLo());
if ((u32)OSGetArenaHi() > (u32)__OSSavedRegionEnd) {
memset((u32)__OSSavedRegionEnd, 0, (u32)OSGetArenaHi() - (u32)__OSSavedRegionEnd);
}
}
}
static void InquiryCallback(s32 result, DVDCommandBlock *block)
{
switch (block->state) {
case 0:
__OSDeviceCode = (u16)(0x8000 | DriveInfo.deviceCode);
break;
default:
__OSDeviceCode = 1;
break;
}
}
void OSInit(void)
{
/*
Initializes the Dolphin operating system.
- most of the main operations get farmed out to other functions
- loading debug info and setting up heap bounds largely happen here
- a lot of OS reporting also gets controlled here
*/
// pretty sure this is the min(/max) amount of pointers etc for the stack to match
BI2Debug *DebugInfo;
void *debugArenaLo;
u32 inputConsoleType;
// check if we've already done all this or not
if ((BOOL)AreWeInitialized == FALSE) { // fantastic name
AreWeInitialized = TRUE; // flag to make sure we don't have to do this again
// SYSTEM //
__OSStartTime = __OSGetSystemTime();
OSDisableInterrupts();
// set some PPC things
PPCDisableSpeculation();
PPCSetFpNonIEEEMode();
// DEBUG //
// load some DVD stuff
BI2DebugFlag = 0; // debug flag from the DVD BI2 header
BootInfo = (OSBootInfo *)OS_BASE_CACHED; // set pointer to BootInfo
__DVDLongFileNameFlag = (u32)0; // flag to tell us whether we make it through the debug loading
// time to grab a bunch of debug info from the DVD
// the address for where the BI2 debug info is, is stored at OS_BI2_DEBUG_ADDRESS
DebugInfo = (BI2Debug *)*((u32 *)OS_BI2_DEBUG_ADDRESS);
// if the debug info address exists, grab some debug info
if (DebugInfo != NULL) {
BI2DebugFlag = &DebugInfo->debugFlag; // debug flag from DVD BI2
__PADSpec = (u32)DebugInfo->padSpec; // some other info from DVD BI2
*((u8 *)DEBUGFLAG_ADDR) = (u8)*BI2DebugFlag; // store flag in mem
*((u8 *)OS_DEBUG_ADDRESS_2) = (u8)__PADSpec; // store other info in mem
}
else if (BootInfo->arenaHi) { // if the top of the heap is already set
BI2DebugFlagHolder = (u32 *)*((u8 *)DEBUGFLAG_ADDR); // grab whatever's stored at 0x800030E8
BI2DebugFlag = (u32 *)&BI2DebugFlagHolder; // flag is then address of flag holder
__PADSpec = (u32) * ((u8 *)OS_DEBUG_ADDRESS_2); // pad spec is whatever's at 0x800030E9
}
__DVDLongFileNameFlag = 1; // we made it through debug!
// HEAP //
// set up bottom of heap (ArenaLo)
// grab address from BootInfo if it exists, otherwise use default __ArenaLo
OSSetArenaLo((BootInfo->arenaLo == NULL) ? __ArenaLo : BootInfo->arenaLo);
// if the input arenaLo is null, and debug flag location exists (and flag is < 2),
// set arenaLo to just past the end of the db stack
if ((BootInfo->arenaLo == NULL) && (BI2DebugFlag != 0) && (*BI2DebugFlag < 2)) {
debugArenaLo = (char *)(((u32)_stack_addr + 0x1f) & ~0x1f);
OSSetArenaLo(debugArenaLo);
}
// set up top of heap (ArenaHi)
// grab address from BootInfo if it exists, otherwise use default __ArenaHi
OSSetArenaHi((BootInfo->arenaHi == NULL) ? __ArenaHi : BootInfo->arenaHi);
// OS INIT AND REPORT //
// initialise a whole bunch of OS stuff
OSExceptionInit();
__OSInitSystemCall();
OSInitAlarm();
__OSModuleInit();
__OSInterruptInit();
__OSSetInterruptHandler(__OS_INTERRUPT_PI_RSW, (void *)__OSResetSWInterruptHandler);
__OSContextInit();
__OSCacheInit();
EXIInit();
SIInit();
__OSInitSram();
__OSThreadInit();
__OSInitAudioSystem();
PPCMthid2(PPCMfhid2() & 0xBFFFFFFF);
if ((BootInfo->consoleType & OS_CONSOLE_DEVELOPMENT) != 0) {
BootInfo->consoleType = OS_CONSOLE_DEVHW1;
}
else {
BootInfo->consoleType = OS_CONSOLE_RETAIL1;
}
BootInfo->consoleType += (__PIRegs[11] & 0xF0000000) >> 28;
if ((BOOL)__OSInIPL == FALSE) {
__OSInitMemoryProtection();
}
// begin OS reporting
OSReport("\nDolphin OS $Revision: 54 $.\n");
OSReport("Kernel built : %s %s\n", "Jun 5 2002", "02:09:12");
OSReport("Console Type : ");
// this is a function in the same file, but it doesn't seem to match
// inputConsoleType = OSGetConsoleType();
// inputConsoleType = (BootInfo == NULL || (inputConsoleType = BootInfo->consoleType) == 0) ?
// 0x10000002 : BootInfo->consoleType;
if (BootInfo == NULL || (inputConsoleType = BootInfo->consoleType) == 0) {
inputConsoleType = OS_CONSOLE_ARTHUR; // default console type
}
else {
inputConsoleType = BootInfo->consoleType;
}
// work out what console type this corresponds to and report it
// consoleTypeSwitchHi = inputConsoleType & 0xF0000000;
inputConsoleType = OSGetConsoleType();
if ((inputConsoleType & 0x10000000) == OS_CONSOLE_RETAIL) { // check "first" byte
OSReport("Retail %d\n", inputConsoleType);
}
else {
switch (inputConsoleType) { // if "first" byte is 2, check "the rest"
case OS_CONSOLE_EMULATOR:
OSReport("Mac Emulator\n");
break;
case OS_CONSOLE_PC_EMULATOR:
OSReport("PC Emulator\n");
break;
case OS_CONSOLE_ARTHUR:
OSReport("EPPC Arthur\n");
break;
case OS_CONSOLE_MINNOW:
OSReport("EPPC Minnow\n");
break;
default:
OSReport("Development HW%d\n", ((u32)inputConsoleType - 0x10000000) - 3);
break;
}
}
// report memory size
OSReport("Memory %d MB\n", (u32)BootInfo->memorySize >> 0x14U);
// report heap bounds
OSReport("Arena : 0x%x - 0x%x\n", OSGetArenaLo(), OSGetArenaHi());
// report OS version
// if location of debug flag exists, and flag is >= 2, enable MetroTRKInterrupts
if (BI2DebugFlag && ((*BI2DebugFlag) >= 2)) {
EnableMetroTRKInterrupts();
}
// free up memory and re-enable things
ClearArena();
OSEnableInterrupts();
// check if we can load OS from IPL; if not, grab it from DVD (?)
if ((BOOL)__OSInIPL == FALSE) {
DVDInit();
if ((BOOL)__OSIsGcam) {
__OSDeviceCode = 0x9000;
return;
}
DCInvalidateRange(&DriveInfo, sizeof(DriveInfo));
DVDInquiryAsync((char *)&DriveBlock, &DriveInfo, InquiryCallback);
}
}
}
static u32 __OSExceptionLocations[] = {
0x00000100,
0x00000200,
0x00000300,
0x00000400,
0x00000500,
0x00000600,
0x00000700,
0x00000800,
0x00000900,
0x00000C00,
0x00000D00,
0x00000F00,
0x00001300,
0x00001400,
0x00001700,
};
// dummy entry points to the OS Exception vector
void __OSEVStart(void);
void __OSEVEnd(void);
void __OSEVSetNumber(void);
void __OSExceptionVector(void);
void __DBVECTOR(void);
void __OSDBINTSTART(void);
void __OSDBINTEND(void);
void __OSDBJUMPSTART(void);
void __OSDBJUMPEND(void);
#define NOP 0x60000000
__OSExceptionHandler __OSSetExceptionHandler(__OSException exception, __OSExceptionHandler handler);
static void OSExceptionInit(void)
{
__OSException exception;
void *destAddr;
// These two vars help us change the exception number embedded
// in the exception handler code.
u32 *opCodeAddr;
u32 oldOpCode;
// Address range of the actual code to be copied.
u8 *handlerStart;
u32 handlerSize;
// Install the first level exception vector.
opCodeAddr = (u32 *)__OSEVSetNumber;
oldOpCode = *opCodeAddr;
handlerStart = (u8 *)__OSEVStart;
handlerSize = (u32)((u8 *)__OSEVEnd - (u8 *)__OSEVStart);
// Install the DB integrator, only if we are the first OSInit to be run
destAddr = (void *)OSPhysicalToCached(OS_DBJUMPPOINT_ADDR);
if (*(u32 *)destAddr == 0) // Lomem should be zero cleared only once by BS2
{
DBPrintf("Installing OSDBIntegrator\n");
memcpy(destAddr, (void *)__OSDBINTSTART, (u32)__OSDBINTEND - (u32)__OSDBINTSTART);
DCFlushRangeNoSync(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART);
__sync();
ICInvalidateRange(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART);
}
// Copy the right vector into the table
for (exception = 0; exception < 15; exception++) {
if (BI2DebugFlag && (*BI2DebugFlag >= 2) && __DBIsExceptionMarked(exception)) {
// this DBPrintf is suspicious.
DBPrintf(">>> OSINIT: exception %d commandeered by TRK\n", exception);
continue;
}
// Modify the copy of code in text before transferring
// to the exception table.
*opCodeAddr = oldOpCode | exception;
// Modify opcodes at __DBVECTOR if necessary
if (__DBIsExceptionMarked(exception)) {
DBPrintf(">>> OSINIT: exception %d vectored to debugger\n", exception);
memcpy((void *)__DBVECTOR, (void *)__OSDBINTEND, (u32)__OSDBJUMPEND - (u32)__OSDBINTEND);
}
else {
// make sure the opcodes are still nop
u32 *ops = (u32 *)__DBVECTOR;
int cb;
for (cb = 0; cb < (u32)__OSDBJUMPEND - (u32)__OSDBINTEND; cb += sizeof(u32)) {
*ops++ = NOP;
}
}
// Install the modified handler.
destAddr = (void *)OSPhysicalToCached(__OSExceptionLocations[(u32)exception]);
memcpy(destAddr, handlerStart, handlerSize);
DCFlushRangeNoSync(destAddr, handlerSize);
__sync();
ICInvalidateRange(destAddr, handlerSize);
}
// initialize pointer to exception table
OSExceptionTable = OSPhysicalToCached(OS_EXCEPTIONTABLE_ADDR);
// install default exception handlers
for (exception = 0; exception < 15; exception++) {
__OSSetExceptionHandler(exception, OSDefaultExceptionHandler);
}
// restore the old opcode, so that we can re-start an application without
// downloading the text segments
*opCodeAddr = oldOpCode;
DBPrintf("Exceptions initialized...\n");
}
static asm void __OSDBIntegrator(void)
{
/* clang-format off */
nofralloc
entry __OSDBINTSTART
li r5, OS_DBINTERFACE_ADDR
mflr r3
stw r3, DB_EXCEPTIONRET_OFFSET(r5)
lwz r3, DB_EXCEPTIONDEST_OFFSET(r5)
oris r3, r3, OS_CACHED_REGION_PREFIX
mtlr r3
li r3, 0x30 // MSR_IR | MSR_DR // turn on memory addressing
mtmsr r3
blr
entry __OSDBINTEND
/* clang-format on */
}
static asm void __OSDBJump(void) {
/* clang-format off */
nofralloc
entry __OSDBJUMPSTART
bla OS_DBJUMPPOINT_ADDR
entry __OSDBJUMPEND
/* clang-format on */
}
__OSExceptionHandler __OSSetExceptionHandler(__OSException exception, __OSExceptionHandler handler)
{
__OSExceptionHandler oldHandler;
oldHandler = OSExceptionTable[exception];
OSExceptionTable[exception] = handler;
return oldHandler;
}
__OSExceptionHandler __OSGetExceptionHandler(__OSException exception)
{
return OSExceptionTable[exception];
}
static asm void OSExceptionVector(void)
{
/* clang-format off */
nofralloc
entry __OSEVStart
// Save r4 into SPRG0
mtsprg 0, r4
// Load current context physical address into r4
lwz r4, OS_CURRENTCONTEXT_PADDR
// Save r3 - r5 into the current context
stw r3, OS_CONTEXT_R3(r4)
mfsprg r3, 0
stw r3, OS_CONTEXT_R4(r4)
stw r5, OS_CONTEXT_R5(r4)
lhz r3, OS_CONTEXT_STATE(r4)
ori r3, r3, OS_CONTEXT_STATE_EXC
sth r3, OS_CONTEXT_STATE(r4)
// Save misc registers
mfcr r3
stw r3, OS_CONTEXT_CR(r4)
mflr r3
stw r3, OS_CONTEXT_LR(r4)
mfctr r3
stw r3, OS_CONTEXT_CTR(r4)
mfxer r3
stw r3, OS_CONTEXT_XER(r4)
mfsrr0 r3
stw r3, OS_CONTEXT_SRR0(r4)
mfsrr1 r3
stw r3, OS_CONTEXT_SRR1(r4)
mr r5, r3
entry __DBVECTOR
nop
// Set SRR1[IR|DR] to turn on address
// translation at the next RFI
mfmsr r3
ori r3, r3, 0x30
mtsrr1 r3
// This lets us change the exception number based on the
// exception we're installing.
entry __OSEVSetNumber
addi r3, 0, 0x0000
// Load current context virtual address into r4
lwz r4, 0xD4
// Check non-recoverable interrupt
rlwinm. r5, r5, 0, MSR_RI_BIT, MSR_RI_BIT
bne recoverable
addis r5, 0, OSDefaultExceptionHandler@ha
addi r5, r5, OSDefaultExceptionHandler@l
mtsrr0 r5
rfi
// NOT REACHED HERE
recoverable:
// Locate exception handler.
rlwinm r5, r3, 2, 22, 29 // r5 contains exception*4
lwz r5, OS_EXCEPTIONTABLE_ADDR(r5)
mtsrr0 r5
// Final state
// r3 - exception number
// r4 - pointer to context
// r5 - garbage
// srr0 - exception handler
// srr1 - address translation enalbed, not yet recoverable
rfi
// NOT REACHED HERE
// The handler will restore state
entry __OSEVEnd
nop
/* clang-format on */
}
void __OSUnhandledException(__OSException exception, OSContext *context, u32 dsisr, u32 dar);
asm void OSDefaultExceptionHandler(register __OSException exception, register OSContext *context)
{
/* clang-format off */
nofralloc
OS_EXCEPTION_SAVE_GPRS(context)
mfdsisr r5
mfdar r6
stwu r1,-8(r1)
b __OSUnhandledException
/* clang-foramt on */
}
void __OSPSInit(void)
{
PPCMthid2(PPCMfhid2() | 0xA0000000);
ICFlashInvalidate();
__sync();
// clang-format off
asm
{
li r3, 0
mtspr GQR0, r3
}
// clang-format on
}
#define DI_CONFIG_IDX 0x9
#define DI_CONFIG_CONFIG_MASK 0xFF
u32 __OSGetDIConfig(void)
{
return (__DIRegs[DI_CONFIG_IDX] & DI_CONFIG_CONFIG_MASK);
}
void OSRegisterVersion(const char *id)
{
OSReport("%s\n", id);
}

199
src/dolphin/os/OSAlarm.c Normal file
View file

@ -0,0 +1,199 @@
#include <dolphin/PPCArch.h>
#include <dolphin/os.h>
#include <dolphin/os/OSPriv.h>
static struct OSAlarmQueue {
OSAlarm *head;
OSAlarm *tail;
} AlarmQueue;
static void DecrementerExceptionHandler(__OSException exception, OSContext *context);
static BOOL OnReset(BOOL final);
void OSInitAlarm(void)
{
if (__OSGetExceptionHandler(8) != DecrementerExceptionHandler) {
AlarmQueue.head = AlarmQueue.tail = NULL;
__OSSetExceptionHandler(8, DecrementerExceptionHandler);
}
}
void OSCreateAlarm(OSAlarm *alarm)
{
alarm->handler = 0;
}
static void SetTimer(OSAlarm *alarm)
{
OSTime delta;
delta = alarm->fire - __OSGetSystemTime();
if (delta < 0) {
PPCMtdec(0);
}
else if (delta < 0x80000000) {
PPCMtdec((u32)delta);
}
else {
PPCMtdec(0x7fffffff);
}
}
static void InsertAlarm(OSAlarm *alarm, OSTime fire, OSAlarmHandler handler)
{
OSAlarm *next;
OSAlarm *prev;
if (0 < alarm->period) {
OSTime time = __OSGetSystemTime();
fire = alarm->start;
if (alarm->start < time) {
fire += alarm->period * ((time - alarm->start) / alarm->period + 1);
}
}
alarm->handler = handler;
alarm->fire = fire;
for (next = AlarmQueue.head; next; next = next->next) {
if (next->fire <= fire) {
continue;
}
alarm->prev = next->prev;
next->prev = alarm;
alarm->next = next;
prev = alarm->prev;
if (prev) {
prev->next = alarm;
}
else {
AlarmQueue.head = alarm;
SetTimer(alarm);
}
return;
}
alarm->next = 0;
prev = AlarmQueue.tail;
AlarmQueue.tail = alarm;
alarm->prev = prev;
if (prev) {
prev->next = alarm;
}
else {
AlarmQueue.head = AlarmQueue.tail = alarm;
SetTimer(alarm);
}
}
void OSSetAlarm(OSAlarm *alarm, OSTime tick, OSAlarmHandler handler)
{
BOOL enabled;
enabled = OSDisableInterrupts();
alarm->period = 0;
InsertAlarm(alarm, __OSGetSystemTime() + tick, handler);
OSRestoreInterrupts(enabled);
}
void OSSetPeriodicAlarm(OSAlarm *alarm, OSTime start, OSTime period, OSAlarmHandler handler)
{
BOOL enabled;
enabled = OSDisableInterrupts();
alarm->period = period;
alarm->start = __OSTimeToSystemTime(start);
InsertAlarm(alarm, 0, handler);
OSRestoreInterrupts(enabled);
}
void OSCancelAlarm(OSAlarm *alarm)
{
OSAlarm *next;
BOOL enabled;
enabled = OSDisableInterrupts();
if (alarm->handler == 0) {
OSRestoreInterrupts(enabled);
return;
}
next = alarm->next;
if (next == 0) {
AlarmQueue.tail = alarm->prev;
}
else {
next->prev = alarm->prev;
}
if (alarm->prev) {
alarm->prev->next = next;
}
else {
AlarmQueue.head = next;
if (next) {
SetTimer(next);
}
}
alarm->handler = 0;
OSRestoreInterrupts(enabled);
}
static void DecrementerExceptionCallback(register __OSException exception, register OSContext *context)
{
OSAlarm *alarm;
OSAlarm *next;
OSAlarmHandler handler;
OSTime time;
OSContext exceptionContext;
time = __OSGetSystemTime();
alarm = AlarmQueue.head;
if (alarm == 0) {
OSLoadContext(context);
}
if (time < alarm->fire) {
SetTimer(alarm);
OSLoadContext(context);
}
next = alarm->next;
AlarmQueue.head = next;
if (next == 0) {
AlarmQueue.tail = 0;
}
else {
next->prev = 0;
}
handler = alarm->handler;
alarm->handler = 0;
if (0 < alarm->period) {
InsertAlarm(alarm, 0, handler);
}
if (AlarmQueue.head) {
SetTimer(AlarmQueue.head);
}
OSDisableScheduler();
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
handler(alarm, context);
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
OSEnableScheduler();
__OSReschedule();
OSLoadContext(context);
}
static asm void DecrementerExceptionHandler(register __OSException exception, register OSContext *context)
{
/* clang-format off */
nofralloc
OS_EXCEPTION_SAVE_GPRS(context)
stwu r1, -8(r1)
b DecrementerExceptionCallback
/* clang-format on */
}

531
src/dolphin/os/OSAlloc.c Normal file
View file

@ -0,0 +1,531 @@
#include <dolphin.h>
#include <dolphin/os.h>
#include <dolphin/os/OSPriv.h>
#define ALIGNMENT 32
#define InRange(cell, arenaStart, arenaEnd) ((u32)arenaStart <= (u32)cell) && ((u32)cell < (u32)arenaEnd)
#define HEADERSIZE 32u
#define MINOBJSIZE 64u
struct Cell {
struct Cell *prev;
struct Cell *next;
long size;
};
struct HeapDesc {
long size;
struct Cell *free;
struct Cell *allocated;
};
volatile int __OSCurrHeap = -1;
static struct HeapDesc *HeapArray;
static int NumHeaps;
static void *ArenaStart;
static void *ArenaEnd;
// functions
static struct Cell *DLAddFront(struct Cell *list, struct Cell *cell);
static struct Cell *DLLookup(struct Cell *list, struct Cell *cell);
static struct Cell *DLExtract(struct Cell *list, struct Cell *cell);
static struct Cell *DLInsert(struct Cell *list, struct Cell *cell);
static int DLOverlap(struct Cell *list, void *start, void *end);
static long DLSize(struct Cell *list);
static struct Cell *DLAddFront(struct Cell *list, struct Cell *cell)
{
cell->next = list;
cell->prev = 0;
if (list) {
list->prev = cell;
}
return cell;
}
static struct Cell *DLLookup(struct Cell *list, struct Cell *cell)
{
for (; list; list = list->next) {
if (list == cell) {
return list;
}
}
return NULL;
}
static struct Cell *DLExtract(struct Cell *list, struct Cell *cell)
{
if (cell->next) {
cell->next->prev = cell->prev;
}
if (cell->prev == NULL) {
return cell->next;
}
cell->prev->next = cell->next;
return list;
}
static struct Cell *DLInsert(struct Cell *list, struct Cell *cell)
{
struct Cell *prev;
struct Cell *next;
for (next = list, prev = NULL; next != 0; prev = next, next = next->next) {
if (cell <= next) {
break;
}
}
cell->next = next;
cell->prev = prev;
if (next) {
next->prev = cell;
if ((u8 *)cell + cell->size == (u8 *)next) {
cell->size += next->size;
next = next->next;
cell->next = next;
if (next) {
next->prev = cell;
}
}
}
if (prev) {
prev->next = cell;
if ((u8 *)prev + prev->size == (u8 *)cell) {
prev->size += cell->size;
prev->next = next;
if (next) {
next->prev = prev;
}
}
return list;
}
return cell;
}
static int DLOverlap(struct Cell *list, void *start, void *end)
{
struct Cell *cell = list;
while (cell) {
if (((start <= cell) && (cell < end)) || ((start < (void *)((u8 *)cell + cell->size)) && ((void *)((u8 *)cell + cell->size) <= end))) {
return 1;
}
cell = cell->next;
}
return 0;
}
static long DLSize(struct Cell *list)
{
struct Cell *cell;
long size;
size = 0;
cell = list;
while (cell) {
size += cell->size;
cell = cell->next;
}
return size;
}
void *OSAllocFromHeap(int heap, unsigned long size)
{
struct HeapDesc *hd;
struct Cell *cell;
struct Cell *newCell;
long leftoverSize;
long requested;
requested = size;
ASSERTMSG1(0x14D, HeapArray, "OSAllocFromHeap(): heap is not initialized.");
ASSERTMSG1(0x14E, (signed long)size > 0, "OSAllocFromHeap(): invalid size.");
ASSERTMSG1(0x14F, heap >= 0 && heap < NumHeaps, "OSAllocFromHeap(): invalid heap handle.");
ASSERTMSG1(0x150, HeapArray[heap].size >= 0, "OSAllocFromHeap(): invalid heap handle.");
hd = &HeapArray[heap];
size += 0x20;
size = (size + 0x1F) & 0xFFFFFFE0;
for (cell = hd->free; cell != NULL; cell = cell->next) {
if ((signed)size <= (signed)cell->size) {
break;
}
}
if (cell == NULL) {
return NULL;
}
ASSERTMSG1(0x168, !((s32)cell & 0x1F), "OSAllocFromHeap(): heap is broken.");
ASSERTMSG1(0x169, cell->hd == NULL, "OSAllocFromHeap(): heap is broken.");
leftoverSize = cell->size - size;
if (leftoverSize < 0x40U) {
hd->free = DLExtract(hd->free, cell);
}
else {
cell->size = size;
newCell = (void *)((u8 *)cell + size);
newCell->size = leftoverSize;
newCell->prev = cell->prev;
newCell->next = cell->next;
if (newCell->next != NULL) {
newCell->next->prev = newCell;
}
if (newCell->prev != NULL) {
newCell->prev->next = newCell;
}
else {
ASSERTMSG1(0x186, hd->free == cell, "OSAllocFromHeap(): heap is broken.");
hd->free = newCell;
}
}
hd->allocated = DLAddFront(hd->allocated, cell);
return (u8 *)cell + 0x20;
}
void *OSAllocFixed(void **rstart, void **rend)
{
int i;
struct Cell *cell;
struct Cell *newCell;
struct HeapDesc *hd;
void *start;
void *end;
void *cellEnd;
start = (void *)((*(u32 *)rstart) & ~((32) - 1));
end = (void *)((*(u32 *)rend + 0x1FU) & ~((32) - 1));
ASSERTMSG1(0x1B0, HeapArray, "OSAllocFixed(): heap is not initialized.");
ASSERTMSG1(0x1B1, (u32)start < (u32)end, "OSAllocFixed(): invalid range.");
ASSERTMSG1(0x1B3, ((u32)ArenaStart <= (u32)start) && ((u32)end <= (u32)ArenaEnd), "OSAllocFixed(): invalid range.");
for (i = 0; i < NumHeaps; i++) {
hd = &HeapArray[i];
if (hd->size >= 0) {
if (DLOverlap(hd->allocated, start, end)) {
return NULL;
}
}
}
for (i = 0; i < NumHeaps; i++) {
hd = &HeapArray[i];
if (hd->size >= 0) {
for (cell = hd->free; cell; cell = cell->next) {
cellEnd = ((u8 *)cell + cell->size);
if (cellEnd > start) {
if (end <= cell) {
break;
}
if ((char *)start - 0x20 <= (char *)cell && cell < end && (start <= cellEnd) && (cellEnd < ((char *)end + 0x40))) {
if (cell < start) {
start = cell;
}
if (end < cellEnd) {
end = cellEnd;
}
hd->free = DLExtract(hd->free, cell);
hd->size -= cell->size;
}
else if ((char *)start - 0x20 <= (char *)cell && cell < end) {
if (cell < start) {
start = cell;
}
ASSERTMSG(0x1F3, MINOBJSIZE <= (char *)cellEnd - (char *)end);
newCell = (struct Cell *)end;
newCell->size = (s32)((char *)cellEnd - (char *)end);
newCell->next = cell->next;
if (newCell->next) {
newCell->next->prev = newCell;
}
newCell->prev = cell->prev;
if (newCell->prev) {
newCell->prev->next = newCell;
}
else {
hd->free = newCell;
}
hd->size -= ((char *)end - (char *)cell);
break;
}
else {
if ((start <= cellEnd) && (cellEnd < ((char *)end + 0x40U))) {
if (end < cellEnd) {
end = cellEnd;
}
ASSERTMSG(0x20C, MINOBJSIZE <= (char *)start - (char *)cell);
hd->size -= ((char *)cellEnd - (char *)start);
cell->size = ((char *)start - (char *)cell);
}
else {
ASSERTMSG(0x213, MINOBJSIZE <= (char *)cellEnd - (char *)end);
newCell = (struct Cell *)end;
newCell->size = ((char *)cellEnd - (char *)end);
newCell->next = cell->next;
if (newCell->next) {
newCell->next->prev = newCell;
}
newCell->prev = cell;
cell->next = newCell;
cell->size = ((char *)start - (char *)cell);
hd->size -= ((char *)end - (char *)start);
break;
}
}
}
}
ASSERTMSG(0x222, 0 <= hd->size);
}
}
ASSERTMSG(0x225, OFFSET(start, ALIGNMENT) == 0);
ASSERTMSG(0x226, OFFSET(end, ALIGNMENT) == 0);
ASSERTMSG(0x227, start < end);
*(u32 *)rstart = (u32)start;
*(u32 *)rend = (u32)end;
return (void *)*(u32 *)rstart;
}
void OSFreeToHeap(int heap, void *ptr)
{
struct HeapDesc *hd;
struct Cell *cell;
ASSERTMSG1(0x23D, HeapArray, "OSFreeToHeap(): heap is not initialized.");
ASSERTMSG1(0x23F, ((u32)ArenaStart + 0x20) <= (u32)ptr && (u32)ptr < (u32)ArenaEnd, "OSFreeToHeap(): invalid pointer.");
ASSERTMSG1(0x240, OFFSET(ptr, ALIGNMENT) == 0, "OSFreeToHeap(): invalid pointer.");
ASSERTMSG1(0x241, HeapArray[heap].size >= 0, "OSFreeToHeap(): invalid heap handle.");
cell = (void *)((u32)ptr - 0x20);
hd = &HeapArray[heap];
ASSERTMSG1(0x246, cell->hd == hd, "OSFreeToHeap(): invalid pointer.");
ASSERTMSG1(0x247, DLLookup(hd->allocated, cell), "OSFreeToHeap(): invalid pointer.");
hd->allocated = DLExtract(hd->allocated, cell);
hd->free = DLInsert(hd->free, cell);
}
int OSSetCurrentHeap(int heap)
{
int prev;
ASSERTMSG1(0x267, HeapArray, "OSSetCurrentHeap(): heap is not initialized.");
ASSERTMSG1(0x268, (heap >= 0) && (heap < NumHeaps), "OSSetCurrentHeap(): invalid heap handle.");
ASSERTMSG1(0x269, HeapArray[heap].size >= 0, "OSSetCurrentHeap(): invalid heap handle.");
prev = __OSCurrHeap;
__OSCurrHeap = heap;
return prev;
}
void *OSInitAlloc(void *arenaStart, void *arenaEnd, int maxHeaps)
{
unsigned long arraySize;
int i;
struct HeapDesc *hd;
ASSERTMSG1(0x283, maxHeaps > 0, "OSInitAlloc(): invalid number of heaps.");
ASSERTMSG1(0x285, (u32)arenaStart < (u32)arenaEnd, "OSInitAlloc(): invalid range.");
ASSERTMSG1(0x288, maxHeaps <= (((u32)arenaEnd - (u32)arenaStart) / 24U), "OSInitAlloc(): too small range.");
arraySize = maxHeaps * sizeof(struct HeapDesc);
HeapArray = arenaStart;
NumHeaps = maxHeaps;
for (i = 0; i < NumHeaps; i++) {
hd = &HeapArray[i];
hd->size = -1;
hd->free = hd->allocated = 0;
}
__OSCurrHeap = -1;
arenaStart = (void *)((u32)((char *)HeapArray + arraySize));
arenaStart = (void *)(((u32)arenaStart + 0x1F) & 0xFFFFFFE0);
ArenaStart = arenaStart;
ArenaEnd = (void *)((u32)arenaEnd & 0xFFFFFFE0);
ASSERTMSG1(0x2A4, ((u32)ArenaEnd - (u32)ArenaStart) >= 0x40U, "OSInitAlloc(): too small range.");
return arenaStart;
}
int OSCreateHeap(void *start, void *end)
{
int heap;
struct HeapDesc *hd;
struct Cell *cell;
ASSERTMSG1(0x2BD, HeapArray, "OSCreateHeap(): heap is not initialized.");
ASSERTMSG1(0x2BE, (u32)start < (u32)end, "OSCreateHeap(): invalid range.");
start = (void *)(((u32)start + 0x1FU) & ~((32) - 1));
end = (void *)(((u32)end) & ~((32) - 1));
ASSERTMSG1(0x2C1, (u32)start < (u32)end, "OSCreateHeap(): invalid range.");
ASSERTMSG1(0x2C3, (u32)ArenaStart <= (u32)start && (u32)end <= (u32)ArenaEnd, "OSCreateHeap(): invalid range.");
ASSERTMSG1(0x2C5, ((u32)end - (u32)start) >= 0x40U, "OSCreateHeap(): too small range.");
for (heap = 0; heap < NumHeaps; heap++) {
hd = &HeapArray[heap];
if (hd->size < 0) {
hd->size = (u32)end - (u32)start;
cell = start;
cell->prev = 0;
cell->next = 0;
cell->size = hd->size;
hd->free = cell;
hd->allocated = 0;
return heap;
}
}
return -1;
}
void OSDestroyHeap(int heap)
{
struct HeapDesc *hd;
long size;
ASSERTMSG1(0x30A, HeapArray, "OSDestroyHeap(): heap is not initialized.");
ASSERTMSG1(0x30B, (heap >= 0) && (heap < NumHeaps), "OSDestroyHeap(): invalid heap handle.");
ASSERTMSG1(0x30C, HeapArray[heap].size >= 0, "OSDestroyHeap(): invalid heap handle.");
hd = &HeapArray[heap];
hd->size = -1;
}
void OSAddToHeap(int heap, void *start, void *end)
{
struct HeapDesc *hd;
struct Cell *cell;
int i;
ASSERTMSG1(0x339, HeapArray, "OSAddToHeap(): heap is not initialized.");
ASSERTMSG1(0x33A, (heap >= 0) && (heap < NumHeaps), "OSAddToHeap(): invalid heap handle.");
ASSERTMSG1(0x33B, HeapArray[heap].size >= 0, "OSAddToHeap(): invalid heap handle.");
hd = &HeapArray[heap];
ASSERTMSG1(0x33F, (u32)start < (u32)end, "OSAddToHeap(): invalid range.");
start = (void *)(((u32)start + 0x1F) & ~((32) - 1));
end = (void *)(((u32)end) & ~((32) - 1));
ASSERTMSG1(0x343, ((u32)end - (u32)start) >= 0x40U, "OSAddToHeap(): too small range.");
ASSERTMSG1(0x345, (u32)ArenaStart <= (u32)start && (u32)end <= (u32)ArenaEnd, "OSAddToHeap(): invalid range.");
cell = (struct Cell *)start;
cell->size = ((char *)end - (char *)start);
hd->size += cell->size;
hd->free = DLInsert(hd->free, cell);
}
// custom macro for OSCheckHeap
#define ASSERTREPORT(line, cond) \
if (!(cond)) { \
OSReport("OSCheckHeap: Failed " #cond " in %d", line); \
return -1; \
}
long OSCheckHeap(int heap)
{
struct HeapDesc *hd;
struct Cell *cell;
long total = 0;
long free = 0;
ASSERTREPORT(0x37D, HeapArray);
ASSERTREPORT(0x37E, 0 <= heap && heap < NumHeaps);
hd = &HeapArray[heap];
ASSERTREPORT(0x381, 0 <= hd->size);
ASSERTREPORT(0x383, hd->allocated == NULL || hd->allocated->prev == NULL);
for (cell = hd->allocated; cell; cell = cell->next) {
ASSERTREPORT(0x386, InRange(cell, ArenaStart, ArenaEnd));
ASSERTREPORT(0x387, OFFSET(cell, ALIGNMENT) == 0);
ASSERTREPORT(0x388, cell->next == NULL || cell->next->prev == cell);
ASSERTREPORT(0x389, MINOBJSIZE <= cell->size);
ASSERTREPORT(0x38A, OFFSET(cell->size, ALIGNMENT) == 0);
total += cell->size;
ASSERTREPORT(0x38D, 0 < total && total <= hd->size);
}
ASSERTREPORT(0x395, hd->free == NULL || hd->free->prev == NULL);
for (cell = hd->free; cell; cell = cell->next) {
ASSERTREPORT(0x398, InRange(cell, ArenaStart, ArenaEnd));
ASSERTREPORT(0x399, OFFSET(cell, ALIGNMENT) == 0);
ASSERTREPORT(0x39A, cell->next == NULL || cell->next->prev == cell);
ASSERTREPORT(0x39B, MINOBJSIZE <= cell->size);
ASSERTREPORT(0x39C, OFFSET(cell->size, ALIGNMENT) == 0);
ASSERTREPORT(0x39D, cell->next == NULL || (char *)cell + cell->size < (char *)cell->next);
total += cell->size;
free = (cell->size + free);
free -= HEADERSIZE;
ASSERTREPORT(0x3A1, 0 < total && total <= hd->size);
}
ASSERTREPORT(0x3A8, total == hd->size);
return free;
}
unsigned long OSReferentSize(void *ptr)
{
struct Cell *cell;
ASSERTMSG1(0x3BB, HeapArray, "OSReferentSize(): heap is not initialized.");
ASSERTMSG1(0x3BD, InRange(ptr, ArenaStart + HEADERSIZE, ArenaEnd), "OSReferentSize(): invalid pointer.");
ASSERTMSG1(0x3BE, !OFFSET(ptr, 32), "OSReferentSize(): invalid pointer.");
cell = (void *)((u32)ptr - HEADERSIZE);
ASSERTMSG1(0x3C2, cell->hd, "OSReferentSize(): invalid pointer.");
ASSERTMSG1(0x3C4, !(((u32)cell->hd - (u32)HeapArray) % 24), "OSReferentSize(): invalid pointer.");
ASSERTMSG1(0x3C6, ((u32)HeapArray <= (u32)cell->hd) && ((u32)cell->hd < (u32)((u32)HeapArray + (NumHeaps * 0x18))),
"OSReferentSize(): invalid pointer.");
ASSERTMSG1(0x3C7, cell->hd->size >= 0, "OSReferentSize(): invalid pointer.");
ASSERTMSG1(0x3C9, DLLookup(cell->hd->allocated, cell), "OSReferentSize(): invalid pointer.");
return (long)((u32)cell->size - HEADERSIZE);
}
void OSDumpHeap(int heap)
{
struct HeapDesc *hd;
struct Cell *cell;
OSReport("\nOSDumpHeap(%d):\n", heap);
ASSERTMSG1(0x3DE, HeapArray, "OSDumpHeap(): heap is not initialized.");
ASSERTMSG1(0x3DF, (heap >= 0) && (heap < NumHeaps), "OSDumpHeap(): invalid heap handle.");
hd = &HeapArray[heap];
if (hd->size < 0) {
OSReport("--------Inactive\n");
return;
}
ASSERTMSG1(0x3E8, OSCheckHeap(heap) >= 0, "OSDumpHeap(): heap is broken.");
OSReport("addr size end prev next\n");
OSReport("--------Allocated\n");
ASSERTMSG1(0x3F5, hd->allocated == NULL || hd->allocated->prev == NULL, "OSDumpHeap(): heap is broken.");
for (cell = hd->allocated; cell; cell = cell->next) {
OSReport("%x %d %x %x %x\n", cell, cell->size, (char *)cell + cell->size, cell->prev, cell->next);
}
OSReport("--------Free\n");
for (cell = hd->free; cell; cell = cell->next) {
OSReport("%x %d %x %x %x\n", cell, cell->size, (char *)cell + cell->size, cell->prev, cell->next);
}
}
void OSVisitAllocated(void (*visitor)(void *, unsigned long))
{
unsigned long heap;
struct Cell *cell;
for (heap = 0; heap < NumHeaps; heap++) {
if (HeapArray[heap].size >= 0) {
for (cell = HeapArray[heap].allocated; cell; cell = cell->next) {
visitor((char *)cell + HEADERSIZE, cell->size);
}
}
}
}

53
src/dolphin/os/OSArena.c Normal file
View file

@ -0,0 +1,53 @@
#include <dolphin/os/OSArena.h>
#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1))
#define TRUNC(n, a) (((u32)(n)) & ~((a)-1))
void *__OSArenaHi;
void *__OSArenaLo = (void *)-1;
void *OSGetArenaHi(void)
{
return __OSArenaHi;
}
void *OSGetArenaLo(void)
{
return __OSArenaLo;
}
void OSSetArenaHi(void *addr)
{
__OSArenaHi = addr;
}
void OSSetArenaLo(void *addr)
{
__OSArenaLo = addr;
}
void *OSAllocFromArenaLo(u32 size, u32 align)
{
void *ptr;
u8 *arenaLo;
ptr = OSGetArenaLo();
arenaLo = ptr = (void *)ROUND(ptr, align);
arenaLo += size;
arenaLo = (u8 *)ROUND(arenaLo, align);
OSSetArenaLo(arenaLo);
return ptr;
}
void *OSAllocFromArenaHi(u32 size, u32 align)
{
void *ptr;
u8 *arenaHi;
arenaHi = OSGetArenaHi();
arenaHi = (u8 *)TRUNC(arenaHi, align);
arenaHi -= size;
arenaHi = ptr = (void *)TRUNC(arenaHi, align);
OSSetArenaHi(arenaHi);
return ptr;
}

View file

@ -0,0 +1,118 @@
#include "types.h"
#include <dolphin/hw_regs.h>
#include <dolphin/os.h>
#ifdef __cplusplus
extern "C" {
#endif
static u8 DSPInitCode[128] = {
// clang-format off
0x02, 0x9F, 0x00, 0x10, 0x02, 0x9F, 0x00, 0x33, 0x02, 0x9F, 0x00, 0x34, 0x02, 0x9F, 0x00, 0x35,
0x02, 0x9F, 0x00, 0x36, 0x02, 0x9F, 0x00, 0x37, 0x02, 0x9F, 0x00, 0x38, 0x02, 0x9F, 0x00, 0x39,
0x12, 0x06, 0x12, 0x03, 0x12, 0x04, 0x12, 0x05, 0x00, 0x80, 0x80, 0x00, 0x00, 0x88, 0xFF, 0xFF,
0x00, 0x84, 0x10, 0x00, 0x00, 0x64, 0x00, 0x1D, 0x02, 0x18, 0x00, 0x00, 0x81, 0x00, 0x1C, 0x1E,
0x00, 0x44, 0x1B, 0x1E, 0x00, 0x84, 0x08, 0x00, 0x00, 0x64, 0x00, 0x27, 0x19, 0x1E, 0x00, 0x00,
0x00, 0xDE, 0xFF, 0xFC, 0x02, 0xA0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x28, 0x16, 0xFC, 0x00, 0x54,
0x16, 0xFD, 0x43, 0x48, 0x00, 0x21, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF,
0x02, 0xFF, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// clang-format on
};
#define __DSPWorkBuffer (void *)0x81000000
void __OSInitAudioSystem(void)
{
u32 r28;
u16 r3;
u32 padding;
memcpy((void *)((u8 *)OSGetArenaHi() - 128), __DSPWorkBuffer, 128);
memcpy(__DSPWorkBuffer, (void *)DSPInitCode, 128);
DCFlushRange(__DSPWorkBuffer, 128);
__DSPRegs[9] = 0x43;
__DSPRegs[5] = 0x8AC;
__DSPRegs[5] |= 1;
while (__DSPRegs[5] & 1)
;
__DSPRegs[0] = 0;
while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000)
;
*(u32 *)&__DSPRegs[16] = 0x1000000;
*(u32 *)&__DSPRegs[18] = 0;
*(u32 *)&__DSPRegs[20] = 0x20;
r3 = __DSPRegs[5];
while (!(r3 & 0x20))
r3 = __DSPRegs[5];
__DSPRegs[5] = r3;
r28 = OSGetTick();
while ((s32)(OSGetTick() - r28) < 0x892)
;
*(u32 *)&__DSPRegs[16] = 0x1000000;
*(u32 *)&__DSPRegs[18] = 0;
*(u32 *)&__DSPRegs[20] = 0x20;
r3 = __DSPRegs[5];
while (!(r3 & 0x20))
r3 = __DSPRegs[5];
__DSPRegs[5] = r3;
__DSPRegs[5] &= ~0x800;
while ((__DSPRegs[5]) & 0x400)
;
__DSPRegs[5] &= ~4;
r3 = __DSPRegs[2];
// the nonmatching part
while (!(r3 & 0x8000))
r3 = __DSPRegs[2];
(void)__DSPRegs[3];
r3 != 42069;
__DSPRegs[5] |= 4;
__DSPRegs[5] = 0x8AC;
__DSPRegs[5] |= 1;
while (__DSPRegs[5] & 1)
;
memcpy(__DSPWorkBuffer, (void *)((u8 *)OSGetArenaHi() - 128), 128);
}
void __OSStopAudioSystem(void)
{
u32 r28;
#define waitUntil(load, mask) \
r28 = (load); \
while (r28 & (mask)) { \
r28 = (load); \
}
__DSPRegs[5] = 0x804;
r28 = __DSPRegs[27];
__DSPRegs[27] = r28 & ~0x8000;
waitUntil(__DSPRegs[5], 0x400);
waitUntil(__DSPRegs[5], 0x200);
__DSPRegs[5] = 0x8ac;
__DSPRegs[0] = 0;
while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000)
;
r28 = OSGetTick();
while ((s32)(OSGetTick() - r28) < 0x2c)
;
__DSPRegs[5] |= 1;
waitUntil(__DSPRegs[5], 0x001);
#undef waitUntil
}
#ifdef __cplusplus
}
#endif

450
src/dolphin/os/OSCache.c Normal file
View file

@ -0,0 +1,450 @@
#include "dolphin/PPCArch.h"
#include "dolphin/os.h"
// Can't use this due to weird condition register issues
// #include "asm_types.h"
#define HID2 920
#include "dolphin/db.h"
/* clang-format off */
asm void DCEnable() {
nofralloc
sync
mfspr r3, HID0
ori r3, r3, 0x4000
mtspr HID0, r3
blr
}
asm void DCInvalidateRange(register void* addr, register u32 nBytes) {
nofralloc
cmplwi nBytes, 0
blelr
clrlwi. r5, addr, 27
beq @2
addi nBytes, nBytes, 32
@2
addi nBytes, nBytes, 31
srwi nBytes, nBytes, 5
mtctr nBytes
@1
dcbi r0, addr
addi addr, addr, 32
bdnz @1
blr
}
asm void DCFlushRange(register void* addr, register u32 nBytes) {
nofralloc
cmplwi nBytes, 0
blelr
clrlwi. r5, addr, 27
beq @2
addi nBytes, nBytes, 32
@2
addi nBytes, nBytes, 31
srwi nBytes, nBytes, 5
mtctr nBytes
@1
dcbf r0, addr
addi addr, addr, 32
bdnz @1
sc
blr
}
asm void DCStoreRange(register void* addr, register u32 nBytes) {
nofralloc
cmplwi nBytes, 0
blelr
clrlwi. r5, addr, 27
beq @2
addi nBytes, nBytes, 32
@2
addi nBytes, nBytes, 31
srwi nBytes, nBytes, 5
mtctr nBytes
@1
dcbst r0, addr
addi addr, addr, 32
bdnz @1
sc
blr
}
asm void DCFlushRangeNoSync(register void* addr, register u32 nBytes) {
nofralloc
cmplwi nBytes, 0
blelr
clrlwi. r5, addr, 27
beq @2
addi nBytes, nBytes, 32
@2
addi nBytes, nBytes, 31
srwi nBytes, nBytes, 5
mtctr nBytes
@1
dcbf r0, addr
addi addr, addr, 32
bdnz @1
blr
}
asm void DCStoreRangeNoSync(register void* addr, register u32 nBytes) {
nofralloc
cmplwi nBytes, 0
blelr
clrlwi. r5, addr, 27
beq @2
addi nBytes, nBytes, 32
@2
addi nBytes, nBytes, 31
srwi nBytes, nBytes, 5
mtctr nBytes
@1
dcbst r0, addr
addi addr, addr, 32
bdnz @1
blr
}
asm void DCZeroRange(register void* addr, register u32 nBytes) {
nofralloc
cmplwi nBytes, 0
blelr
clrlwi. r5, addr, 27
beq @2
addi nBytes, nBytes, 32
@2
addi nBytes, nBytes, 31
srwi nBytes, nBytes, 5
mtctr nBytes
@1
dcbz r0, addr
addi addr, addr, 32
bdnz @1
blr
}
asm void ICInvalidateRange(register void* addr, register u32 nBytes) {
nofralloc
cmplwi nBytes, 0
blelr
clrlwi. r5, addr, 27
beq @2
addi nBytes, nBytes, 32
@2
addi nBytes, nBytes, 31
srwi nBytes, nBytes, 5
mtctr nBytes
@1
icbi r0, addr
addi addr, addr, 32
bdnz @1
sync
isync
blr
}
asm void ICFlashInvalidate() {
nofralloc
mfspr r3, HID0
ori r3, r3, 0x800
mtspr HID0, r3
blr
}
asm void ICEnable() {
nofralloc
isync
mfspr r3, HID0
ori r3, r3, 0x8000
mtspr HID0, r3
blr
}
#define LC_LINES 512
#define CACHE_LINES 1024
asm void __LCEnable() {
nofralloc
mfmsr r5
ori r5, r5, 0x1000
mtmsr r5
lis r3, OS_CACHED_REGION_PREFIX
li r4, CACHE_LINES
mtctr r4
_touchloop:
dcbt 0,r3
dcbst 0,r3
addi r3,r3,32
bdnz _touchloop
mfspr r4, HID2
oris r4, r4, 0x100F
mtspr HID2, r4
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
lis r3, LC_BASE_PREFIX
ori r3, r3, 0x0002
mtspr DBAT3L, r3
ori r3, r3, 0x01fe
mtspr DBAT3U, r3
isync
lis r3, LC_BASE_PREFIX
li r6, LC_LINES
mtctr r6
li r6, 0
_lockloop:
dcbz_l r6, r3
addi r3, r3, 32
bdnz+ _lockloop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
blr
}
void LCEnable() {
BOOL enabled;
enabled = OSDisableInterrupts();
__LCEnable();
OSRestoreInterrupts(enabled);
}
asm void LCDisable() {
nofralloc
lis r3, LC_BASE_PREFIX
li r4, LC_LINES
mtctr r4
@1
dcbi r0, r3
addi r3, r3, 32
bdnz @1
mfspr r4, HID2
rlwinm r4, r4, 0, 4, 2
mtspr HID2, r4
blr
}
asm void LCLoadBlocks(register void* destTag, register void* srcAddr, register u32 numBlocks) {
nofralloc
rlwinm r6, numBlocks, 30, 27, 31
rlwinm srcAddr, srcAddr, 0, 4, 31
or r6, r6, srcAddr
mtspr DMA_U, r6
rlwinm r6, numBlocks, 2, 28, 29
or r6, r6, destTag
ori r6, r6, 0x12
mtspr DMA_L, r6
blr
}
asm void LCStoreBlocks(register void* destAddr, register void* srcTag, register u32 numBlocks) {
nofralloc
rlwinm r6, numBlocks, 30, 27, 31
rlwinm destAddr, destAddr, 0, 4, 31
or r6, r6, destAddr
mtspr DMA_U, r6
rlwinm r6, numBlocks, 2, 28, 29
or r6, r6, srcTag
ori r6, r6, 0x2
mtspr DMA_L, r6
blr
}
/* clang-format on */
u32 LCLoadData(register void *destAddr, register void *srcAddr, register u32 nBytes)
{
u32 numBlocks = (nBytes + 31) / 32;
u32 numTransactions = (numBlocks + 128 - 1) / 128;
while (numBlocks > 0) {
if (numBlocks < 128) {
LCLoadBlocks(destAddr, srcAddr, numBlocks);
numBlocks = 0;
}
else {
LCLoadBlocks(destAddr, srcAddr, 0);
numBlocks -= 128;
destAddr = (void *)((u32)destAddr + 4096);
srcAddr = (void *)((u32)srcAddr + 4096);
}
}
return numTransactions;
}
u32 LCStoreData(void *destAddr, void *srcAddr, u32 nBytes)
{
u32 numBlocks = (nBytes + 31) / 32;
u32 numTransactions = (numBlocks + 128 - 1) / 128;
while (numBlocks > 0) {
if (numBlocks < 128) {
LCStoreBlocks(destAddr, srcAddr, numBlocks);
numBlocks = 0;
}
else {
LCStoreBlocks(destAddr, srcAddr, 0);
numBlocks -= 128;
destAddr = (void *)((u32)destAddr + 4096);
srcAddr = (void *)((u32)srcAddr + 4096);
}
}
return numTransactions;
}
/* clang-format off */
asm u32 LCQueueLength() {
nofralloc
mfspr r4, HID2
rlwinm r3, r4, 8, 28, 31
blr
}
asm void LCQueueWait(register u32 len) {
nofralloc
addi len, len, 1
@1
mfspr r4, HID2
rlwinm r4, r4, 8, 28, 31
cmpw cr2, r4, r3
bge cr2, @1
blr
}
/* clang-format on */
static void L2Disable(void)
{
__sync();
PPCMtl2cr(PPCMfl2cr() & ~0x80000000);
__sync();
}
void L2GlobalInvalidate(void)
{
L2Disable();
PPCMtl2cr(PPCMfl2cr() | 0x00200000);
while (PPCMfl2cr() & 0x00000001u)
;
PPCMtl2cr(PPCMfl2cr() & ~0x00200000);
while (PPCMfl2cr() & 0x00000001u) {
DBPrintf(">>> L2 INVALIDATE : SHOULD NEVER HAPPEN\n");
}
}
static void L2Init(void)
{
u32 oldMSR;
oldMSR = PPCMfmsr();
__sync();
PPCMtmsr(MSR_IR | MSR_DR);
__sync();
L2Disable();
L2GlobalInvalidate();
PPCMtmsr(oldMSR);
}
void L2Enable(void)
{
PPCMtl2cr((PPCMfl2cr() | L2CR_L2E) & ~L2CR_L2I);
}
void DMAErrorHandler(OSError error, OSContext *context, ...)
{
u32 hid2 = PPCMfhid2();
OSReport("Machine check received\n");
OSReport("HID2 = 0x%x SRR1 = 0x%x\n", hid2, context->srr1);
if (!(hid2 & (HID2_DCHERR | HID2_DNCERR | HID2_DCMERR | HID2_DQOERR)) || !(context->srr1 & SRR1_DMA_BIT)) {
OSReport("Machine check was not DMA/locked cache related\n");
OSDumpContext(context);
PPCHalt();
}
OSReport("DMAErrorHandler(): An error occurred while processing DMA.\n");
OSReport("The following errors have been detected and cleared :\n");
if (hid2 & HID2_DCHERR) {
OSReport("\t- Requested a locked cache tag that was already in the cache\n");
}
if (hid2 & HID2_DNCERR) {
OSReport("\t- DMA attempted to access normal cache\n");
}
if (hid2 & HID2_DCMERR) {
OSReport("\t- DMA missed in data cache\n");
}
if (hid2 & HID2_DQOERR) {
OSReport("\t- DMA queue overflowed\n");
}
// write hid2 back to clear the error bits
PPCMthid2(hid2);
}
void __OSCacheInit()
{
if (!(PPCMfhid0() & HID0_ICE)) {
ICEnable();
DBPrintf("L1 i-caches initialized\n");
}
if (!(PPCMfhid0() & HID0_DCE)) {
DCEnable();
DBPrintf("L1 d-caches initialized\n");
}
if (!(PPCMfl2cr() & L2CR_L2E)) {
L2Init();
L2Enable();
DBPrintf("L2 cache initialized\n");
}
OSSetErrorHandler(OS_ERROR_MACHINE_CHECK, DMAErrorHandler);
DBPrintf("Locked cache machine check handler installed\n");
}

555
src/dolphin/os/OSContext.c Normal file
View file

@ -0,0 +1,555 @@
#include <dolphin/db.h>
#include <dolphin/os.h>
#include <dolphin/os/OSPriv.h>
#define HID2 920
volatile OSContext *__OSCurrentContext : (OS_BASE_CACHED | 0x00D4);
volatile OSContext *__OSFPUContext : (OS_BASE_CACHED | 0x00D8);
static asm void __OSLoadFPUContext(register u32, register OSContext *fpuContext)
{
// clang-format off
nofralloc
lhz r5, fpuContext->state;
clrlwi. r5, r5, 31
beq _return
lfd fp0, OS_CONTEXT_FPSCR(fpuContext)
mtfsf 0xFF, fp0
mfspr r5, HID2
rlwinm. r5, r5, 3, 31, 31
beq _regular_FPRs
psq_l fp0, OS_CONTEXT_PSF0(fpuContext), 0, 0
psq_l fp1, OS_CONTEXT_PSF1(fpuContext), 0, 0
psq_l fp2, OS_CONTEXT_PSF2(fpuContext), 0, 0
psq_l fp3, OS_CONTEXT_PSF3(fpuContext), 0, 0
psq_l fp4, OS_CONTEXT_PSF4(fpuContext), 0, 0
psq_l fp5, OS_CONTEXT_PSF5(fpuContext), 0, 0
psq_l fp6, OS_CONTEXT_PSF6(fpuContext), 0, 0
psq_l fp7, OS_CONTEXT_PSF7(fpuContext), 0, 0
psq_l fp8, OS_CONTEXT_PSF8(fpuContext), 0, 0
psq_l fp9, OS_CONTEXT_PSF9(fpuContext), 0, 0
psq_l fp10, OS_CONTEXT_PSF10(fpuContext), 0, 0
psq_l fp11, OS_CONTEXT_PSF11(fpuContext), 0, 0
psq_l fp12, OS_CONTEXT_PSF12(fpuContext), 0, 0
psq_l fp13, OS_CONTEXT_PSF13(fpuContext), 0, 0
psq_l fp14, OS_CONTEXT_PSF14(fpuContext), 0, 0
psq_l fp15, OS_CONTEXT_PSF15(fpuContext), 0, 0
psq_l fp16, OS_CONTEXT_PSF16(fpuContext), 0, 0
psq_l fp17, OS_CONTEXT_PSF17(fpuContext), 0, 0
psq_l fp18, OS_CONTEXT_PSF18(fpuContext), 0, 0
psq_l fp19, OS_CONTEXT_PSF19(fpuContext), 0, 0
psq_l fp20, OS_CONTEXT_PSF20(fpuContext), 0, 0
psq_l fp21, OS_CONTEXT_PSF21(fpuContext), 0, 0
psq_l fp22, OS_CONTEXT_PSF22(fpuContext), 0, 0
psq_l fp23, OS_CONTEXT_PSF23(fpuContext), 0, 0
psq_l fp24, OS_CONTEXT_PSF24(fpuContext), 0, 0
psq_l fp25, OS_CONTEXT_PSF25(fpuContext), 0, 0
psq_l fp26, OS_CONTEXT_PSF26(fpuContext), 0, 0
psq_l fp27, OS_CONTEXT_PSF27(fpuContext), 0, 0
psq_l fp28, OS_CONTEXT_PSF28(fpuContext), 0, 0
psq_l fp29, OS_CONTEXT_PSF29(fpuContext), 0, 0
psq_l fp30, OS_CONTEXT_PSF30(fpuContext), 0, 0
psq_l fp31, OS_CONTEXT_PSF31(fpuContext), 0, 0
_regular_FPRs:
lfd fp0, fpuContext->fpr[0]
lfd fp1, fpuContext->fpr[1]
lfd fp2, fpuContext->fpr[2]
lfd fp3, fpuContext->fpr[3]
lfd fp4, fpuContext->fpr[4]
lfd fp5, fpuContext->fpr[5]
lfd fp6, fpuContext->fpr[6]
lfd fp7, fpuContext->fpr[7]
lfd fp8, fpuContext->fpr[8]
lfd fp9, fpuContext->fpr[9]
lfd fp10, fpuContext->fpr[10]
lfd fp11, fpuContext->fpr[11]
lfd fp12, fpuContext->fpr[12]
lfd fp13, fpuContext->fpr[13]
lfd fp14, fpuContext->fpr[14]
lfd fp15, fpuContext->fpr[15]
lfd fp16, fpuContext->fpr[16]
lfd fp17, fpuContext->fpr[17]
lfd fp18, fpuContext->fpr[18]
lfd fp19, fpuContext->fpr[19]
lfd fp20, fpuContext->fpr[20]
lfd fp21, fpuContext->fpr[21]
lfd fp22, fpuContext->fpr[22]
lfd fp23, fpuContext->fpr[23]
lfd fp24, fpuContext->fpr[24]
lfd fp25, fpuContext->fpr[25]
lfd fp26, fpuContext->fpr[26]
lfd fp27, fpuContext->fpr[27]
lfd fp28, fpuContext->fpr[28]
lfd fp29, fpuContext->fpr[29]
lfd fp30, fpuContext->fpr[30]
lfd fp31, fpuContext->fpr[31]
_return:
blr
// clang-format on
}
static asm void __OSSaveFPUContext(register u32, register u32, register OSContext *fpuContext)
{
// clang-format off
nofralloc
lhz r3, fpuContext->state
ori r3, r3, 1
sth r3, fpuContext->state
stfd fp0, fpuContext->fpr[0]
stfd fp1, fpuContext->fpr[1]
stfd fp2, fpuContext->fpr[2]
stfd fp3, fpuContext->fpr[3]
stfd fp4, fpuContext->fpr[4]
stfd fp5, fpuContext->fpr[5]
stfd fp6, fpuContext->fpr[6]
stfd fp7, fpuContext->fpr[7]
stfd fp8, fpuContext->fpr[8]
stfd fp9, fpuContext->fpr[9]
stfd fp10, fpuContext->fpr[10]
stfd fp11, fpuContext->fpr[11]
stfd fp12, fpuContext->fpr[12]
stfd fp13, fpuContext->fpr[13]
stfd fp14, fpuContext->fpr[14]
stfd fp15, fpuContext->fpr[15]
stfd fp16, fpuContext->fpr[16]
stfd fp17, fpuContext->fpr[17]
stfd fp18, fpuContext->fpr[18]
stfd fp19, fpuContext->fpr[19]
stfd fp20, fpuContext->fpr[20]
stfd fp21, fpuContext->fpr[21]
stfd fp22, fpuContext->fpr[22]
stfd fp23, fpuContext->fpr[23]
stfd fp24, fpuContext->fpr[24]
stfd fp25, fpuContext->fpr[25]
stfd fp26, fpuContext->fpr[26]
stfd fp27, fpuContext->fpr[27]
stfd fp28, fpuContext->fpr[28]
stfd fp29, fpuContext->fpr[29]
stfd fp30, fpuContext->fpr[30]
stfd fp31, fpuContext->fpr[31]
mffs fp0
stfd fp0, OS_CONTEXT_FPSCR(fpuContext)
lfd fp0, fpuContext->fpr[0]
mfspr r3, HID2
rlwinm. r3, r3, 3, 31, 31
bc 12, 2, _return
psq_st fp0, OS_CONTEXT_PSF0(fpuContext), 0, 0
psq_st fp1, OS_CONTEXT_PSF1(fpuContext), 0, 0
psq_st fp2, OS_CONTEXT_PSF2(fpuContext), 0, 0
psq_st fp3, OS_CONTEXT_PSF3(fpuContext), 0, 0
psq_st fp4, OS_CONTEXT_PSF4(fpuContext), 0, 0
psq_st fp5, OS_CONTEXT_PSF5(fpuContext), 0, 0
psq_st fp6, OS_CONTEXT_PSF6(fpuContext), 0, 0
psq_st fp7, OS_CONTEXT_PSF7(fpuContext), 0, 0
psq_st fp8, OS_CONTEXT_PSF8(fpuContext), 0, 0
psq_st fp9, OS_CONTEXT_PSF9(fpuContext), 0, 0
psq_st fp10, OS_CONTEXT_PSF10(fpuContext), 0, 0
psq_st fp11, OS_CONTEXT_PSF11(fpuContext), 0, 0
psq_st fp12, OS_CONTEXT_PSF12(fpuContext), 0, 0
psq_st fp13, OS_CONTEXT_PSF13(fpuContext), 0, 0
psq_st fp14, OS_CONTEXT_PSF14(fpuContext), 0, 0
psq_st fp15, OS_CONTEXT_PSF15(fpuContext), 0, 0
psq_st fp16, OS_CONTEXT_PSF16(fpuContext), 0, 0
psq_st fp17, OS_CONTEXT_PSF17(fpuContext), 0, 0
psq_st fp18, OS_CONTEXT_PSF18(fpuContext), 0, 0
psq_st fp19, OS_CONTEXT_PSF19(fpuContext), 0, 0
psq_st fp20, OS_CONTEXT_PSF20(fpuContext), 0, 0
psq_st fp21, OS_CONTEXT_PSF21(fpuContext), 0, 0
psq_st fp22, OS_CONTEXT_PSF22(fpuContext), 0, 0
psq_st fp23, OS_CONTEXT_PSF23(fpuContext), 0, 0
psq_st fp24, OS_CONTEXT_PSF24(fpuContext), 0, 0
psq_st fp25, OS_CONTEXT_PSF25(fpuContext), 0, 0
psq_st fp26, OS_CONTEXT_PSF26(fpuContext), 0, 0
psq_st fp27, OS_CONTEXT_PSF27(fpuContext), 0, 0
psq_st fp28, OS_CONTEXT_PSF28(fpuContext), 0, 0
psq_st fp29, OS_CONTEXT_PSF29(fpuContext), 0, 0
psq_st fp30, OS_CONTEXT_PSF30(fpuContext), 0, 0
psq_st fp31, OS_CONTEXT_PSF31(fpuContext), 0, 0
_return:
blr
// clang-format on
}
asm void OSLoadFPUContext(register OSContext *fpuContext)
{
// clang-format off
nofralloc
addi r4, fpuContext, 0
b __OSLoadFPUContext
// clang-format on
}
asm void OSSaveFPUContext(register OSContext *fpuContext)
{
// clang-format off
nofralloc
addi r5, fpuContext, 0
b __OSSaveFPUContext
// clang-format on
}
asm void OSSetCurrentContext(register OSContext *context) {
// clang-format off
nofralloc
addis r4, r0, OS_CACHED_REGION_PREFIX
stw context, 0x00D4(r4)
clrlwi r5, context, 2
stw r5, 0x00C0(r4)
lwz r5, 0x00D8(r4)
cmpw r5, context
bne _disableFPU
lwz r6, context->srr1
ori r6, r6, 0x2000
stw r6, context->srr1
mfmsr r6
ori r6, r6, 2
mtmsr r6
blr
_disableFPU:
lwz r6, context->srr1
rlwinm r6, r6, 0, 19, 17
stw r6, context->srr1
mfmsr r6
rlwinm r6, r6, 0, 19, 17
ori r6, r6, 2
mtmsr r6
isync
blr
// clang-format on
}
OSContext *OSGetCurrentContext(void)
{
return (OSContext *)__OSCurrentContext;
}
asm u32 OSSaveContext(register OSContext *context)
{
// clang-format off
nofralloc
stmw r13, context->gpr[13]
mfspr r0, GQR1
stw r0, context->gqr[1]
mfspr r0, GQR2
stw r0, context->gqr[2]
mfspr r0, GQR3
stw r0, context->gqr[3]
mfspr r0, GQR4
stw r0, context->gqr[4]
mfspr r0, GQR5
stw r0, context->gqr[5]
mfspr r0, GQR6
stw r0, context->gqr[6]
mfspr r0, GQR7
stw r0, context->gqr[7]
mfcr r0
stw r0, context->cr
mflr r0
stw r0, context->lr
stw r0, context->srr0
mfmsr r0
stw r0, context->srr1
mfctr r0
stw r0, context->ctr
mfxer r0
stw r0, context->xer
stw r1, context->gpr[1]
stw r2, context->gpr[2]
li r0, 0x1
stw r0, context->gpr[3]
li r3, 0
blr
// clang-format on
}
asm void OSLoadContext(register OSContext *context)
{
// clang-format off
nofralloc
lis r4, __RAS_OSDisableInterrupts_begin@ha
lwz r6, 0x198(context)
addi r5, r4, __RAS_OSDisableInterrupts_begin@l
cmplw r6, r5
blt srr0_not_in_disableintr
lis r4, __RAS_OSDisableInterrupts_end@ha
addi r0, r4, __RAS_OSDisableInterrupts_end@l
cmplw r6, r0
bgt srr0_not_in_disableintr
stw r5, 0x198(context)
srr0_not_in_disableintr:
lwz r0, 0(context)
lwz r1, 4(context)
lwz r2, 8(context)
lhz r4, 0x1a2(context)
rlwinm. r5, r4, 0, 0x1e, 0x1e
beq load_saved_gprs
rlwinm r4, r4, 0, 0x1f, 0x1d
sth r4, 0x1a2(context)
lmw r5, 0x14(context)
b load_special_regs
load_saved_gprs:
lmw r13, 0x34(context)
load_special_regs:
lwz r4, 0x1a8(context)
mtspr 0x391, r4
lwz r4, 0x1ac(context)
mtspr 0x392, r4
lwz r4, 0x1b0(context)
mtspr 0x393, r4
lwz r4, 0x1b4(context)
mtspr 0x394, r4
lwz r4, 0x1b8(context)
mtspr 0x395, r4
lwz r4, 0x1bc(context)
mtspr 0x396, r4
lwz r4, 0x1c0(context)
mtspr 0x397, r4
lwz r4, 0x80(context)
mtcrf 0xff, r4
lwz r4, 0x84(context)
mtlr r4
lwz r4, 0x88(context)
mtctr r4
lwz r4, 0x8c(context)
mtxer r4
mfmsr r4
rlwinm r4, r4, 0, 0x11, 0xf
rlwinm r4, r4, 0, 0x1f, 0x1d
mtmsr r4
lwz r4, 0x198(context)
mtspr 0x1a, r4
lwz r4, 0x19c(context)
mtspr 0x1b, r4
lwz r4, 0x10(context)
lwz context, 0xc(context)
rfi
// clang-format on
}
asm u32 OSGetStackPointer()
{
// clang-format off
nofralloc
mr r3, r1
blr
// clang-format on
}
asm u32 OSSwitchStack(register u32 newsp)
{
// clang-format off
nofralloc
mr r5, r1
mr r1, newsp
mr r3, r5
blr
// clang-format on
}
asm int OSSwitchFiber(register u32 pc, register u32 newsp)
{
// clang-format off
nofralloc
mflr r0
mr r5, r1
stwu r5, -8(newsp)
mr r1, newsp
stw r0, 4(r5)
mtlr pc
blrl
lwz r5, 0(r1)
lwz r0, 4(r5)
mtlr r0
mr r1, r5
blr
// clang-format on
}
void OSClearContext(register OSContext *context)
{
context->mode = 0;
context->state = 0;
if (context == __OSFPUContext)
__OSFPUContext = NULL;
}
asm void OSInitContext(register OSContext *context, register u32 pc, register u32 newsp)
{
// clang-format off
nofralloc
stw pc, OS_CONTEXT_SRR0(context)
stw newsp, OS_CONTEXT_R1(context)
li r11, 0
ori r11, r11, 0x00008000 | 0x00000020 | 0x00000010 | 0x00000002 | 0x00001000
stw r11, OS_CONTEXT_SRR1(context)
li r0, 0x0
stw r0, OS_CONTEXT_CR(context)
stw r0, OS_CONTEXT_XER(context)
stw r2, OS_CONTEXT_R2(context)
stw r13, OS_CONTEXT_R13(context)
stw r0, OS_CONTEXT_R3(context)
stw r0, OS_CONTEXT_R4(context)
stw r0, OS_CONTEXT_R5(context)
stw r0, OS_CONTEXT_R6(context)
stw r0, OS_CONTEXT_R7(context)
stw r0, OS_CONTEXT_R8(context)
stw r0, OS_CONTEXT_R9(context)
stw r0, OS_CONTEXT_R10(context)
stw r0, OS_CONTEXT_R11(context)
stw r0, OS_CONTEXT_R12(context)
stw r0, OS_CONTEXT_R14(context)
stw r0, OS_CONTEXT_R15(context)
stw r0, OS_CONTEXT_R16(context)
stw r0, OS_CONTEXT_R17(context)
stw r0, OS_CONTEXT_R18(context)
stw r0, OS_CONTEXT_R19(context)
stw r0, OS_CONTEXT_R20(context)
stw r0, OS_CONTEXT_R21(context)
stw r0, OS_CONTEXT_R22(context)
stw r0, OS_CONTEXT_R23(context)
stw r0, OS_CONTEXT_R24(context)
stw r0, OS_CONTEXT_R25(context)
stw r0, OS_CONTEXT_R26(context)
stw r0, OS_CONTEXT_R27(context)
stw r0, OS_CONTEXT_R28(context)
stw r0, OS_CONTEXT_R29(context)
stw r0, OS_CONTEXT_R30(context)
stw r0, OS_CONTEXT_R31(context)
stw r0, OS_CONTEXT_GQR0(context)
stw r0, OS_CONTEXT_GQR1(context)
stw r0, OS_CONTEXT_GQR2(context)
stw r0, OS_CONTEXT_GQR3(context)
stw r0, OS_CONTEXT_GQR4(context)
stw r0, OS_CONTEXT_GQR5(context)
stw r0, OS_CONTEXT_GQR6(context)
stw r0, OS_CONTEXT_GQR7(context)
b OSClearContext
// clang-format on
}
void OSDumpContext(OSContext *context)
{
u32 i;
u32 *p;
OSReport("------------------------- Context 0x%08x -------------------------\n", context);
for (i = 0; i < 16; ++i) {
OSReport("r%-2d = 0x%08x (%14d) r%-2d = 0x%08x (%14d)\n", i, context->gpr[i], context->gpr[i], i + 16, context->gpr[i + 16],
context->gpr[i + 16]);
}
OSReport("LR = 0x%08x CR = 0x%08x\n", context->lr, context->cr);
OSReport("SRR0 = 0x%08x SRR1 = 0x%08x\n", context->srr0, context->srr1);
OSReport("\nGQRs----------\n");
for (i = 0; i < 4; ++i) {
OSReport("gqr%d = 0x%08x \t gqr%d = 0x%08x\n", i, context->gqr[i], i + 4, context->gqr[i + 4]);
}
if (context->state & OS_CONTEXT_STATE_FPSAVED) {
OSContext *currentContext;
OSContext fpuContext;
BOOL enabled;
enabled = OSDisableInterrupts();
currentContext = OSGetCurrentContext();
OSClearContext(&fpuContext);
OSSetCurrentContext(&fpuContext);
OSReport("\n\nFPRs----------\n");
for (i = 0; i < 32; i += 2) {
OSReport("fr%d \t= %d \t fr%d \t= %d\n", i, (u32)context->fpr[i], i + 1, (u32)context->fpr[i + 1]);
}
OSReport("\n\nPSFs----------\n");
for (i = 0; i < 32; i += 2) {
OSReport("ps%d \t= 0x%x \t ps%d \t= 0x%x\n", i, (u32)context->psf[i], i + 1, (u32)context->psf[i + 1]);
}
OSClearContext(&fpuContext);
OSSetCurrentContext(currentContext);
OSRestoreInterrupts(enabled);
}
OSReport("\nAddress: Back Chain LR Save\n");
for (i = 0, p = (u32 *)context->gpr[1]; p && (u32)p != 0xffffffff && i++ < 16; p = (u32 *)*p) {
OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]);
}
}
static asm void OSSwitchFPUContext(register __OSException exception, register OSContext *context)
{
// clang-format off
nofralloc
mfmsr r5
ori r5, r5, 0x2000
mtmsr r5
isync
lwz r5, OS_CONTEXT_SRR1(context)
ori r5, r5, 0x2000
mtsrr1 r5
addis r3, r0, OS_CACHED_REGION_PREFIX
lwz r5, 0x00D8(r3)
stw context, 0x00D8(r3)
cmpw r5, r4
beq _restoreAndExit
cmpwi r5, 0x0
beq _loadNewFPUContext
bl __OSSaveFPUContext
_loadNewFPUContext:
bl __OSLoadFPUContext
_restoreAndExit:
lwz r3, OS_CONTEXT_CR(context)
mtcr r3
lwz r3, OS_CONTEXT_LR(context)
mtlr r3
lwz r3, OS_CONTEXT_SRR0(context)
mtsrr0 r3
lwz r3, OS_CONTEXT_CTR(context)
mtctr r3
lwz r3, OS_CONTEXT_XER(context)
mtxer r3
lhz r3, context->state
rlwinm r3, r3, 0, 31, 29
sth r3, context->state
lwz r5, OS_CONTEXT_R5(context)
lwz r3, OS_CONTEXT_R3(context)
lwz r4, OS_CONTEXT_R4(context)
rfi
// clang-format on
}
void __OSContextInit(void)
{
__OSSetExceptionHandler(__OS_EXCEPTION_FLOATING_POINT, OSSwitchFPUContext);
__OSFPUContext = NULL;
DBPrintf("FPU-unavailable handler installed\n");
}

115
src/dolphin/os/OSError.c Normal file
View file

@ -0,0 +1,115 @@
#include <dolphin/PPCArch.h>
#include <dolphin/hw_regs.h>
#include <dolphin/os.h>
#include <stdio.h>
#include <dolphin/os/OSPriv.h>
OSThread *__OSCurrentThread : (OS_BASE_CACHED | 0x00E4);
OSThreadQueue __OSActiveThreadQueue : (OS_BASE_CACHED | 0x00DC);
volatile OSContext *__OSFPUContext : (OS_BASE_CACHED | 0x00D8);
OSErrorHandler __OSErrorTable[OS_ERROR_MAX];
#define FPSCR_ENABLE (FPSCR_VE | FPSCR_OE | FPSCR_UE | FPSCR_ZE | FPSCR_XE)
__declspec(weak) void OSReport(const char *msg, ...)
{
va_list args;
va_start(args, msg);
vprintf(msg, args);
va_end(args);
}
__declspec(weak) void OSVReport(const char *msg, va_list list)
{
vprintf(msg, list);
}
__declspec(weak) void OSPanic(const char *file, int line, const char *msg, ...)
{
va_list marker;
u32 i;
u32 *p;
OSDisableInterrupts();
va_start(marker, msg);
vprintf(msg, marker);
va_end(marker);
OSReport(" in \"%s\" on line %d.\n", file, line);
OSReport("\nAddress: Back Chain LR Save\n");
for (i = 0, p = (u32 *)OSGetStackPointer(); p && (u32)p != 0xffffffff && i++ < 16; p = (u32 *)*p) {
OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]);
}
PPCHalt();
}
OSErrorHandler OSSetErrorHandler(OSError error, OSErrorHandler handler)
{
OSErrorHandler oldHandler;
oldHandler = __OSErrorTable[error];
__OSErrorTable[error] = handler;
return oldHandler;
}
void __OSUnhandledException(__OSException exception, OSContext *context, u32 dsisr, u32 dar)
{
if (!(context->srr1 & MSR_RI)) {
OSReport("Non-recoverable Exception %d", exception);
}
else {
if (__OSErrorTable[exception]) {
OSDisableScheduler();
__OSErrorTable[exception](exception, context, dsisr, dar);
OSEnableScheduler();
__OSReschedule();
OSLoadContext(context);
}
if (exception == OS_ERROR_DECREMENTER) {
OSLoadContext(context);
}
OSReport("Unhandled Exception %d", exception);
}
OSReport("\n");
OSDumpContext(context);
OSReport("\nDSISR = 0x%08x DAR = 0x%08x\n", dsisr, dar);
OSReport("TB = 0x%016llx\n", OSGetTime());
switch (exception) {
case __OS_EXCEPTION_DSI:
OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access "
"invalid address 0x%x (read from DAR)\n",
context->srr0, dar);
break;
case __OS_EXCEPTION_ISI:
OSReport("\nAttempted to fetch instruction from invalid address 0x%x "
"(read from SRR0)\n",
context->srr0);
break;
case __OS_EXCEPTION_ALIGNMENT:
OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access "
"unaligned address 0x%x (read from DAR)\n",
context->srr0, dar);
break;
case __OS_EXCEPTION_PROGRAM:
OSReport("\nProgram exception : Possible illegal instruction/operation "
"at or around 0x%x (read from SRR0)\n",
context->srr0, dar);
break;
case OS_ERROR_PROTECTION:
OSReport("\n");
OSReport("AI DMA Address = 0x%04x%04x\n", __DSPRegs[0x00000018], __DSPRegs[0x00000018 + 1]);
OSReport("ARAM DMA Address = 0x%04x%04x\n", __DSPRegs[0x00000010], __DSPRegs[0x00000010 + 1]);
OSReport("DI DMA Address = 0x%08x\n", __DIRegs[0x00000005]);
break;
}
OSReport("\nLast interrupt (%d): SRR0 = 0x%08x TB = 0x%016llx\n", __OSLastInterrupt, __OSLastInterruptSrr0, __OSLastInterruptTime);
PPCHalt();
}

323
src/dolphin/os/OSFont.c Normal file
View file

@ -0,0 +1,323 @@
#include <dolphin/OSRtcPriv.h>
#include <dolphin/hw_regs.h>
#include <dolphin/os.h>
static OSFontHeader *FontData;
static u8 *SheetImage;
static u8 *WidthTable;
static int CharsInSheet;
static u16 HankakuToCode[] = { 0x20C, 0x20D, 0x20E, 0x20F, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21A, 0x21B, 0x21C,
0x21D, 0x21E, 0x21F, 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22A, 0x22B, 0x22C, 0x22D, 0x22E, 0x22F, 0x230, 0x231,
0x232, 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23A, 0x23B, 0x23C, 0x23D, 0x23E, 0x23F, 0x240, 0x241, 0x242, 0x243, 0x244, 0x245, 0x246,
0x247, 0x248, 0x249, 0x24A, 0x24B, 0x24C, 0x24D, 0x24E, 0x24F, 0x250, 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B,
0x25C, 0x25D, 0x25E, 0x25F, 0x260, 0x261, 0x262, 0x263, 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C,
0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C,
0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x26B, 0x26C, 0x26D, 0x26E, 0x26F, 0x270, 0x271, 0x272, 0x273, 0x274, 0x275, 0x276, 0x277, 0x278,
0x279, 0x27A, 0x27B, 0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, 0x282, 0x283, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28A, 0x28B, 0x28C, 0x28D,
0x28E, 0x28F, 0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, 0x29A, 0x29B, 0x29C, 0x29D, 0x29E, 0x29F, 0x2A0, 0x2A1, 0x2A2,
0x2A3, 0x2A4, 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9 };
static u16 Zenkaku2Code[] = { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, 0x009, 0x00A, 0x00B, 0x00C, 0x00D, 0x00E, 0x00F, 0x010,
0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, 0x018, 0x019, 0x01A, 0x01B, 0x01C, 0x01D, 0x01E, 0x01F, 0x020, 0x021, 0x022, 0x023, 0x024, 0x025,
0x026, 0x027, 0x028, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x03A,
0x03B, 0x03C, 0x03D, 0x03E, 0x03F, 0x040, 0x041, 0x042, 0x043, 0x044, 0x045, 0x046, 0x047, 0x048, 0x049, 0x04A, 0x04B, 0x04C, 0x04D, 0x04E, 0x04F,
0x050, 0x051, 0x052, 0x053, 0x054, 0x055, 0x056, 0x057, 0x058, 0x059, 0x05A, 0x05B, 0x05C, 0x05D, 0x05E, 0x05F, 0x060, 0x061, 0x062, 0x063, 0x064,
0x065, 0x066, 0x067, 0x068, 0x069, 0x06A, 0x06B, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x06C, 0x06D, 0x06E,
0x06F, 0x070, 0x071, 0x072, 0x073, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x074, 0x075, 0x076, 0x077, 0x078, 0x079, 0x07A, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x07B, 0x07C, 0x07D, 0x07E, 0x07F, 0x080, 0x081, 0x082, 0x083, 0x084, 0x085,
0x086, 0x087, 0x088, 0x089, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x08A, 0x08B, 0x08C, 0x08D, 0x08E, 0x08F, 0x090, 0x091, 0x000, 0x000,
0x000, 0x000, 0x092, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x093, 0x094, 0x095,
0x096, 0x097, 0x098, 0x099, 0x09A, 0x09B, 0x09C, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x09D, 0x09E, 0x09F, 0x0A0, 0x0A1, 0x0A2, 0x0A3,
0x0A4, 0x0A5, 0x0A6, 0x0A7, 0x0A8, 0x0A9, 0x0AA, 0x0AB, 0x0AC, 0x0AD, 0x0AE, 0x0AF, 0x0B0, 0x0B1, 0x0B2, 0x0B3, 0x0B4, 0x0B5, 0x0B6, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x0B7, 0x0B8, 0x0B9, 0x0BA, 0x0BB, 0x0BC, 0x0BD, 0x0BE, 0x0BF, 0x0C0, 0x0C1, 0x0C2, 0x0C3, 0x0C4, 0x0C5, 0x0C6, 0x0C7,
0x0C8, 0x0C9, 0x0CA, 0x0CB, 0x0CC, 0x0CD, 0x0CE, 0x0CF, 0x0D0, 0x000, 0x000, 0x000, 0x000, 0x0D1, 0x0D2, 0x0D3, 0x0D4, 0x0D5, 0x0D6, 0x0D7, 0x0D8,
0x0D9, 0x0DA, 0x0DB, 0x0DC, 0x0DD, 0x0DE, 0x0DF, 0x0E0, 0x0E1, 0x0E2, 0x0E3, 0x0E4, 0x0E5, 0x0E6, 0x0E7, 0x0E8, 0x0E9, 0x0EA, 0x0EB, 0x0EC, 0x0ED,
0x0EE, 0x0EF, 0x0F0, 0x0F1, 0x0F2, 0x0F3, 0x0F4, 0x0F5, 0x0F6, 0x0F7, 0x0F8, 0x0F9, 0x0FA, 0x0FB, 0x0FC, 0x0FD, 0x0FE, 0x0FF, 0x100, 0x101, 0x102,
0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, 0x10B, 0x10C, 0x10D, 0x10E, 0x10F, 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117,
0x118, 0x119, 0x11A, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121, 0x122, 0x123, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12A, 0x12B, 0x12C, 0x12D, 0x12E, 0x12F, 0x130, 0x131, 0x132, 0x133, 0x134, 0x135, 0x136,
0x137, 0x138, 0x139, 0x13A, 0x13B, 0x13C, 0x13D, 0x13E, 0x13F, 0x140, 0x141, 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A, 0x14B,
0x14C, 0x14D, 0x14E, 0x14F, 0x150, 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, 0x15A, 0x15B, 0x15C, 0x15D, 0x15E, 0x15F, 0x160,
0x161, 0x162, 0x163, 0x164, 0x165, 0x166, 0x167, 0x168, 0x169, 0x16A, 0x16B, 0x16C, 0x16D, 0x16E, 0x16F, 0x170, 0x171, 0x172, 0x173, 0x174, 0x175,
0x176, 0x177, 0x178, 0x179, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x17A, 0x17B, 0x17C, 0x17D, 0x17E, 0x17F, 0x180, 0x181, 0x182,
0x183, 0x184, 0x185, 0x186, 0x187, 0x188, 0x189, 0x18A, 0x18B, 0x18C, 0x18D, 0x18E, 0x18F, 0x190, 0x191, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, 0x198, 0x199, 0x19A, 0x19B, 0x19C, 0x19D, 0x19E, 0x19F, 0x1A0, 0x1A1, 0x1A2, 0x1A3, 0x1A4,
0x1A5, 0x1A6, 0x1A7, 0x1A8, 0x1A9, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x1AA, 0x1AB, 0x1AC, 0x1AD, 0x1AE, 0x1AF, 0x1B0, 0x1B1, 0x1B2, 0x1B3, 0x1B4, 0x1B5, 0x1B6, 0x1B7, 0x1B8, 0x1B9, 0x1BA, 0x1BB, 0x1BC, 0x1BD,
0x1BE, 0x1BF, 0x1C0, 0x1C1, 0x1C2, 0x1C3, 0x1C4, 0x1C5, 0x1C6, 0x1C7, 0x1C8, 0x1C9, 0x1CA, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x1CB, 0x1CC, 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1D5, 0x1D6, 0x1D7, 0x1D8,
0x1D9, 0x1DA, 0x1DB, 0x1DC, 0x1DD, 0x1DE, 0x1DF, 0x1E0, 0x1E1, 0x1E2, 0x1E3, 0x1E4, 0x1E5, 0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1EA, 0x1EB, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x1EC, 0x1ED, 0x1EE, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, 0x1F5,
0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, 0x1FD, 0x1FE, 0x1FF, 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20A,
0x20B, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x20C,
0x20D, 0x20E, 0x20F, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21A, 0x21B, 0x21C, 0x21D, 0x21E, 0x21F, 0x220, 0x221,
0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22A, 0x22B, 0x22C, 0x22D, 0x22E, 0x22F, 0x230, 0x231, 0x232, 0x233, 0x234, 0x235, 0x236,
0x237, 0x238, 0x239, 0x23A, 0x23B, 0x23C, 0x23D, 0x23E, 0x23F, 0x240, 0x241, 0x242, 0x243, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24A, 0x24B,
0x24C, 0x24D, 0x24E, 0x24F, 0x250, 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B, 0x25C, 0x25D, 0x25E, 0x25F, 0x260,
0x261, 0x262, 0x263, 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x26B, 0x26C, 0x26D, 0x26E, 0x26F, 0x270, 0x271, 0x272, 0x273, 0x274, 0x275,
0x276, 0x277, 0x278, 0x279, 0x27A, 0x27B, 0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, 0x282, 0x283, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28A,
0x28B, 0x28C, 0x28D, 0x28E, 0x28F, 0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, 0x29A, 0x29B, 0x29C, 0x29D, 0x29E, 0x29F,
0x2A0, 0x2A1, 0x2A2, 0x2A3, 0x2A4, 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9, 0x2AA, 0x2AB, 0x2AC, 0x2AD, 0x2AE, 0x2AF, 0x2B0, 0x2B1, 0x2B2, 0x2B3, 0x2B4,
0x2B5, 0x2B6, 0x2B7, 0x2B8, 0x2B9, 0x2BA, 0x2BB, 0x2BC, 0x2BD, 0x2BE, 0x2BF, 0x2C0, 0x2C1, 0x2C2, 0x2C3, 0x2C4, 0x2C5, 0x2C6, 0x2C7, 0x2C8, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x2C9, 0x2CA,
0x2CB, 0x2CC, 0x2CD, 0x2CE, 0x2CF, 0x2D0, 0x2D1, 0x2D2, 0x2D3, 0x2D4, 0x2D5, 0x2D6, 0x2D7, 0x2D8, 0x2D9, 0x2DA, 0x2DB, 0x2DC, 0x2DD, 0x2DE, 0x2DF,
0x2E0, 0x2E1, 0x2E2, 0x2E3, 0x2E4, 0x2E5, 0x2E6, 0x000, 0x2E7, 0x2E8, 0x2E9, 0x2EA, 0x2EB, 0x2EC, 0x2ED, 0x2EE, 0x2EF, 0x2F0, 0x2F1, 0x2F2, 0x2F3,
0x2F4, 0x2F5, 0x2F6, 0x2F7, 0x2F8, 0x2F9, 0x2FA, 0x2FB, 0x2FC, 0x2FD, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x2FE, 0x2FF, 0x300,
0x301, 0x302, 0x303, 0x304, 0x305, 0x306, 0x307, 0x308, 0x309, 0x30A, 0x30B, 0x30C, 0x30D, 0x30E, 0x30F, 0x310, 0x311, 0x312, 0x313, 0x314, 0x315,
0x316, 0x317, 0x318, 0x319, 0x31A, 0x31B, 0x000 };
static int GetFontCode(unsigned short code)
{
if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) {
if (code >= 0x20 && code <= 0xDF) {
return HankakuToCode[code - 0x20];
}
if (code > 0x889E) {
int i = ((code >> 8) - 0x88) * 188;
int j = (code & 0xFF) - 0x40;
if (j >= 0x40) {
j--;
}
return (i + j + 0x2BE);
}
if (code < 0x879E) {
int i = ((code >> 8) - 0x81) * 188;
int j = (code & 0xFF) - 0x40;
if (j >= 0x40) {
j--;
}
return Zenkaku2Code[i + j];
}
}
else if (code > 0x20 && code <= 0xFF) {
return code - 0x20;
}
else {
return 0;
}
}
static void Decode(unsigned char *s, unsigned char *d)
{
int i;
int j;
int k;
int p;
int q;
int r7; // huh? DWARF info says these 2 variables might be register names and not actual names.
int r25;
int cnt;
int os;
unsigned int flag;
unsigned int code;
os = *(int *)(s + 0x4);
r7 = *(int *)(s + 0x8);
r25 = *(int *)(s + 0xC);
q = 0;
flag = 0;
p = 16;
do {
// Get next mask
if (flag == 0) {
code = *(u32 *)(s + p);
p += sizeof(u32);
flag = sizeof(u32) * 8;
}
// Non-linked chunk
if (code & 0x80000000) {
d[q++] = s[r25++];
}
// Linked chunk
else {
// Read offset from link table
j = s[r7] << 8 | s[r7 + 1];
r7 += sizeof(u16);
// Apply offset
k = q - (j & 0x0FFF);
cnt = j >> 12;
if (cnt == 0) {
cnt = s[r25++] + 0x12;
}
else {
cnt += 2;
}
// Copy chunk
for (i = 0; i < cnt; i++, q++, k++) {
d[q] = d[k - 1];
}
}
// Prepare next mask bit
code <<= 1;
flag--;
} while (q < os);
}
static u32 GetFontSize(u8 *buf)
{
if (buf[0] == 'Y' && buf[1] == 'a' && buf[2] == 'y') {
return *(u32 *)(buf + 0x4);
}
return 0;
}
u16 OSGetFontEncode(void)
{
static u16 fontEncode = 0xFFFF;
if (fontEncode <= 1) {
return fontEncode;
}
switch (*(int *)OSPhysicalToCached(0xCC)) {
case VI_NTSC:
fontEncode = (__VIRegs[VI_DTV_STAT] & 2) ? OS_FONT_ENCODE_SJIS : OS_FONT_ENCODE_ANSI;
break;
case VI_PAL:
case VI_MPAL:
case VI_DEBUG:
case VI_DEBUG_PAL:
case VI_EURGB60:
default:
fontEncode = OS_FONT_ENCODE_ANSI;
}
return fontEncode;
}
static void ReadROM(void *buf, int length, int offset)
{
int len;
while (length > 0) {
len = (length <= 0x100) ? length : 0x100;
length -= len;
while (!__OSReadROM(buf, len, offset)) {
;
}
offset += len;
(u8 *)buf += len;
}
}
static u32 ReadFont(void *img)
{
if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) {
ReadROM(img, OS_FONT_ROM_SIZE_SJIS, 0x1AFF00);
}
else {
ReadROM(img, OS_FONT_ROM_SIZE_ANSI, 0x1FCF00);
}
return GetFontSize(img);
}
u32 OSLoadFont(OSFontHeader *fontData, void *temp)
{
u32 size;
SheetImage = NULL;
size = ReadFont(temp);
if (size) {
Decode(temp, (void *)fontData);
FontData = fontData;
WidthTable = (u8 *)FontData + FontData->widthTable;
CharsInSheet = FontData->sheetColumn * FontData->sheetRow;
}
return size;
}
char *OSGetFontTexel(char *string, void *image, long pos, long stride, long *width)
{
unsigned short code;
unsigned char *src;
unsigned char *dst;
int fontCode;
int sheet;
int numChars;
int row;
int column;
int x;
int y;
int offsetSrc;
int offsetDst;
unsigned char *colorIndex;
unsigned char *imageSrc;
// ASSERTLINE(0x1F6, FontData && !SheetImage);
code = *string;
if (code == '\0') {
return string;
}
string++;
if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) {
if ((((code >= 0x80) && (code <= 0x9F)) || ((code >= 0xE0) && (code <= 0xFF))) && ((s8)*string != 0U)) {
code = (code << 8) | (*string++); // Shift-JIS encoded byte
}
}
colorIndex = &FontData->c0;
// ASSERTLINE(0x209, FontData->sheetFormat == GX_TF_I4);
fontCode = GetFontCode(code);
sheet = fontCode / CharsInSheet;
numChars = fontCode - (sheet * CharsInSheet);
row = numChars / FontData->sheetColumn;
column = (numChars - (row * FontData->sheetColumn));
row *= FontData->cellHeight;
column *= FontData->cellWidth;
imageSrc = (u8 *)FontData + FontData->sheetImage;
imageSrc += (sheet * FontData->sheetSize) / 2;
for (y = 0; y < FontData->cellHeight; y++) {
for (x = 0; x < FontData->cellWidth; x++) {
src = imageSrc + (((FontData->sheetWidth / 8) * 32) / 2) * ((row + y) / 8);
src += ((column + x) / 8) * 16;
src += ((row + y) % 8) * 2;
src += ((column + x) % 8) / 4;
offsetSrc = (column + x) % 4;
dst = (u8 *)image + ((y / 8) * (((stride * 4) / 8) * 32));
dst += (((pos + x) / 8) * 32);
dst += ((y % 8) * 4);
dst += ((pos + x) % 8) / 2;
offsetDst = (pos + x) % 2;
*dst |= colorIndex[*src >> (6 - (offsetSrc * 2)) & 3] & ((offsetDst != 0) ? 0x0F : 0xF0);
}
}
*width = WidthTable[fontCode];
return string;
}

View file

@ -0,0 +1,434 @@
#include <dolphin/hw_regs.h>
#include <dolphin/os.h>
#include <dolphin/os/OSPriv.h>
static asm void ExternalInterruptHandler(register __OSException exception, register OSContext *context);
static __OSInterruptHandler *InterruptHandlerTable;
static OSInterruptMask InterruptPrioTable[] = {
OS_INTERRUPTMASK_PI_ERROR,
OS_INTERRUPTMASK_PI_DEBUG,
OS_INTERRUPTMASK_MEM,
OS_INTERRUPTMASK_PI_RSW,
OS_INTERRUPTMASK_PI_VI,
OS_INTERRUPTMASK_PI_PE,
OS_INTERRUPTMASK_PI_HSP,
OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP | OS_INTERRUPTMASK_AI | OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI_SI
| OS_INTERRUPTMASK_PI_DI,
OS_INTERRUPTMASK_DSP_AI,
OS_INTERRUPTMASK_PI_CP,
0xFFFFFFFF,
};
asm BOOL OSDisableInterrupts(void)
{
// clang-format off
nofralloc
entry __RAS_OSDisableInterrupts_begin
mfmsr r3
rlwinm r4, r3, 0, 17, 15
mtmsr r4
rlwinm r3, r3, 17, 31, 31
entry __RAS_OSDisableInterrupts_end
blr
// clang-format on
}
asm BOOL OSEnableInterrupts(void)
{
// clang-format off
nofralloc
mfmsr r3
ori r4, r3, 0x8000
mtmsr r4
rlwinm r3, r3, 17, 31, 31
blr
// clang-format on
}
asm BOOL OSRestoreInterrupts(register BOOL level) {
// clang-format off
nofralloc
cmpwi level, 0
mfmsr r4
beq _disable
ori r5, r4, 0x8000
b _restore
_disable:
rlwinm r5, r4, 0, 17, 15
_restore:
mtmsr r5
rlwinm r3, r4, 17, 31, 31
blr
// clang-format on
}
__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler)
{
__OSInterruptHandler oldHandler;
oldHandler = InterruptHandlerTable[interrupt];
InterruptHandlerTable[interrupt] = handler;
return oldHandler;
}
__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt)
{
return InterruptHandlerTable[interrupt];
}
void __OSInterruptInit(void)
{
InterruptHandlerTable = OSPhysicalToCached(0x3040);
memset(InterruptHandlerTable, 0, __OS_INTERRUPT_MAX * sizeof(__OSInterruptHandler));
*(OSInterruptMask *)OSPhysicalToCached(0x00C4) = 0;
*(OSInterruptMask *)OSPhysicalToCached(0x00C8) = 0;
__PIRegs[1] = 0xf0;
__OSMaskInterrupts(OS_INTERRUPTMASK_MEM | OS_INTERRUPTMASK_DSP | OS_INTERRUPTMASK_AI | OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI);
__OSSetExceptionHandler(4, ExternalInterruptHandler);
}
u32 SetInterruptMask(OSInterruptMask mask, OSInterruptMask current)
{
u32 reg;
switch (__cntlzw(mask)) {
case __OS_INTERRUPT_MEM_0:
case __OS_INTERRUPT_MEM_1:
case __OS_INTERRUPT_MEM_2:
case __OS_INTERRUPT_MEM_3:
case __OS_INTERRUPT_MEM_ADDRESS:
reg = 0;
if (!(current & OS_INTERRUPTMASK_MEM_0))
reg |= 0x1;
if (!(current & OS_INTERRUPTMASK_MEM_1))
reg |= 0x2;
if (!(current & OS_INTERRUPTMASK_MEM_2))
reg |= 0x4;
if (!(current & OS_INTERRUPTMASK_MEM_3))
reg |= 0x8;
if (!(current & OS_INTERRUPTMASK_MEM_ADDRESS))
reg |= 0x10;
__MEMRegs[0x0000000e] = (u16)reg;
mask &= ~OS_INTERRUPTMASK_MEM;
break;
case __OS_INTERRUPT_DSP_AI:
case __OS_INTERRUPT_DSP_ARAM:
case __OS_INTERRUPT_DSP_DSP:
reg = __DSPRegs[0x00000005];
reg &= ~0x1F8;
if (!(current & OS_INTERRUPTMASK_DSP_AI))
reg |= 0x10;
if (!(current & OS_INTERRUPTMASK_DSP_ARAM))
reg |= 0x40;
if (!(current & OS_INTERRUPTMASK_DSP_DSP))
reg |= 0x100;
__DSPRegs[0x00000005] = (u16)reg;
mask &= ~OS_INTERRUPTMASK_DSP;
break;
case __OS_INTERRUPT_AI_AI:
reg = __AIRegs[0];
reg &= ~0x2C;
if (!(current & OS_INTERRUPTMASK_AI_AI))
reg |= 0x4;
__AIRegs[0] = reg;
mask &= ~OS_INTERRUPTMASK_AI;
break;
case __OS_INTERRUPT_EXI_0_EXI:
case __OS_INTERRUPT_EXI_0_TC:
case __OS_INTERRUPT_EXI_0_EXT:
reg = __EXIRegs[0];
reg &= ~0x2C0F;
if (!(current & OS_INTERRUPTMASK_EXI_0_EXI))
reg |= 0x1;
if (!(current & OS_INTERRUPTMASK_EXI_0_TC))
reg |= 0x4;
if (!(current & OS_INTERRUPTMASK_EXI_0_EXT))
reg |= 0x400;
__EXIRegs[0] = reg;
mask &= ~OS_INTERRUPTMASK_EXI_0;
break;
case __OS_INTERRUPT_EXI_1_EXI:
case __OS_INTERRUPT_EXI_1_TC:
case __OS_INTERRUPT_EXI_1_EXT:
reg = __EXIRegs[5];
reg &= ~0xC0F;
if (!(current & OS_INTERRUPTMASK_EXI_1_EXI))
reg |= 0x1;
if (!(current & OS_INTERRUPTMASK_EXI_1_TC))
reg |= 0x4;
if (!(current & OS_INTERRUPTMASK_EXI_1_EXT))
reg |= 0x400;
__EXIRegs[5] = reg;
mask &= ~OS_INTERRUPTMASK_EXI_1;
break;
case __OS_INTERRUPT_EXI_2_EXI:
case __OS_INTERRUPT_EXI_2_TC:
reg = __EXIRegs[10];
reg &= ~0xF;
if (!(current & OS_INTERRUPTMASK_EXI_2_EXI))
reg |= 0x1;
if (!(current & OS_INTERRUPTMASK_EXI_2_TC))
reg |= 0x4;
__EXIRegs[10] = reg;
mask &= ~OS_INTERRUPTMASK_EXI_2;
break;
case __OS_INTERRUPT_PI_CP:
case __OS_INTERRUPT_PI_SI:
case __OS_INTERRUPT_PI_DI:
case __OS_INTERRUPT_PI_RSW:
case __OS_INTERRUPT_PI_ERROR:
case __OS_INTERRUPT_PI_VI:
case __OS_INTERRUPT_PI_DEBUG:
case __OS_INTERRUPT_PI_PE_TOKEN:
case __OS_INTERRUPT_PI_PE_FINISH:
case __OS_INTERRUPT_PI_HSP:
reg = 0xF0;
if (!(current & OS_INTERRUPTMASK_PI_CP)) {
reg |= 0x800;
}
if (!(current & OS_INTERRUPTMASK_PI_SI)) {
reg |= 0x8;
}
if (!(current & OS_INTERRUPTMASK_PI_DI)) {
reg |= 0x4;
}
if (!(current & OS_INTERRUPTMASK_PI_RSW)) {
reg |= 0x2;
}
if (!(current & OS_INTERRUPTMASK_PI_ERROR)) {
reg |= 0x1;
}
if (!(current & OS_INTERRUPTMASK_PI_VI)) {
reg |= 0x100;
}
if (!(current & OS_INTERRUPTMASK_PI_DEBUG)) {
reg |= 0x1000;
}
if (!(current & OS_INTERRUPTMASK_PI_PE_TOKEN)) {
reg |= 0x200;
}
if (!(current & OS_INTERRUPTMASK_PI_PE_FINISH)) {
reg |= 0x400;
}
if (!(current & OS_INTERRUPTMASK_PI_HSP)) {
reg |= 0x2000;
}
__PIRegs[1] = reg;
mask &= ~OS_INTERRUPTMASK_PI;
break;
default:
break;
}
return mask;
}
OSInterruptMask OSGetInterruptMask(void)
{
return *(OSInterruptMask *)OSPhysicalToCached(0x00C8);
}
OSInterruptMask OSSetInterruptMask(OSInterruptMask local)
{
BOOL enabled;
OSInterruptMask global;
OSInterruptMask prev;
OSInterruptMask mask;
enabled = OSDisableInterrupts();
global = *(OSInterruptMask *)OSPhysicalToCached(0x00C4);
prev = *(OSInterruptMask *)OSPhysicalToCached(0x00C8);
mask = (global | prev) ^ local;
*(OSInterruptMask *)OSPhysicalToCached(0x00C8) = local;
while (mask) {
mask = SetInterruptMask(mask, global | local);
}
OSRestoreInterrupts(enabled);
return prev;
}
OSInterruptMask __OSMaskInterrupts(OSInterruptMask global)
{
BOOL enabled;
OSInterruptMask prev;
OSInterruptMask local;
OSInterruptMask mask;
enabled = OSDisableInterrupts();
prev = *(OSInterruptMask *)OSPhysicalToCached(0x00C4);
local = *(OSInterruptMask *)OSPhysicalToCached(0x00C8);
mask = ~(prev | local) & global;
global |= prev;
*(OSInterruptMask *)OSPhysicalToCached(0x00C4) = global;
while (mask) {
mask = SetInterruptMask(mask, global | local);
}
OSRestoreInterrupts(enabled);
return prev;
}
OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask global)
{
BOOL enabled;
OSInterruptMask prev;
OSInterruptMask local;
OSInterruptMask mask;
enabled = OSDisableInterrupts();
prev = *(OSInterruptMask *)OSPhysicalToCached(0x00C4);
local = *(OSInterruptMask *)OSPhysicalToCached(0x00C8);
mask = (prev | local) & global;
global = prev & ~global;
*(OSInterruptMask *)OSPhysicalToCached(0x00C4) = global;
while (mask) {
mask = SetInterruptMask(mask, global | local);
}
OSRestoreInterrupts(enabled);
return prev;
}
volatile OSTime __OSLastInterruptTime;
volatile __OSInterrupt __OSLastInterrupt;
volatile u32 __OSLastInterruptSrr0;
void __OSDispatchInterrupt(__OSException exception, OSContext *context)
{
u32 intsr;
u32 reg;
OSInterruptMask cause;
OSInterruptMask unmasked;
OSInterruptMask *prio;
__OSInterrupt interrupt;
__OSInterruptHandler handler;
intsr = __PIRegs[0];
intsr &= ~0x00010000;
if (intsr == 0 || (intsr & __PIRegs[1]) == 0) {
OSLoadContext(context);
}
cause = 0;
if (intsr & 0x00000080) {
reg = __MEMRegs[15];
if (reg & 0x1)
cause |= OS_INTERRUPTMASK_MEM_0;
if (reg & 0x2)
cause |= OS_INTERRUPTMASK_MEM_1;
if (reg & 0x4)
cause |= OS_INTERRUPTMASK_MEM_2;
if (reg & 0x8)
cause |= OS_INTERRUPTMASK_MEM_3;
if (reg & 0x10)
cause |= OS_INTERRUPTMASK_MEM_ADDRESS;
}
if (intsr & 0x00000040) {
reg = __DSPRegs[5];
if (reg & 0x8)
cause |= OS_INTERRUPTMASK_DSP_AI;
if (reg & 0x20)
cause |= OS_INTERRUPTMASK_DSP_ARAM;
if (reg & 0x80)
cause |= OS_INTERRUPTMASK_DSP_DSP;
}
if (intsr & 0x00000020) {
reg = __AIRegs[0];
if (reg & 0x8)
cause |= OS_INTERRUPTMASK_AI_AI;
}
if (intsr & 0x00000010) {
reg = __EXIRegs[0];
if (reg & 0x2)
cause |= OS_INTERRUPTMASK_EXI_0_EXI;
if (reg & 0x8)
cause |= OS_INTERRUPTMASK_EXI_0_TC;
if (reg & 0x800)
cause |= OS_INTERRUPTMASK_EXI_0_EXT;
reg = __EXIRegs[5];
if (reg & 0x2)
cause |= OS_INTERRUPTMASK_EXI_1_EXI;
if (reg & 0x8)
cause |= OS_INTERRUPTMASK_EXI_1_TC;
if (reg & 0x800)
cause |= OS_INTERRUPTMASK_EXI_1_EXT;
reg = __EXIRegs[10];
if (reg & 0x2)
cause |= OS_INTERRUPTMASK_EXI_2_EXI;
if (reg & 0x8)
cause |= OS_INTERRUPTMASK_EXI_2_TC;
}
if (intsr & 0x00002000)
cause |= OS_INTERRUPTMASK_PI_HSP;
if (intsr & 0x00001000)
cause |= OS_INTERRUPTMASK_PI_DEBUG;
if (intsr & 0x00000400)
cause |= OS_INTERRUPTMASK_PI_PE_FINISH;
if (intsr & 0x00000200)
cause |= OS_INTERRUPTMASK_PI_PE_TOKEN;
if (intsr & 0x00000100)
cause |= OS_INTERRUPTMASK_PI_VI;
if (intsr & 0x00000008)
cause |= OS_INTERRUPTMASK_PI_SI;
if (intsr & 0x00000004)
cause |= OS_INTERRUPTMASK_PI_DI;
if (intsr & 0x00000002)
cause |= OS_INTERRUPTMASK_PI_RSW;
if (intsr & 0x00000800)
cause |= OS_INTERRUPTMASK_PI_CP;
if (intsr & 0x00000001)
cause |= OS_INTERRUPTMASK_PI_ERROR;
unmasked = cause & ~(*(OSInterruptMask *)OSPhysicalToCached(0x00C4) | *(OSInterruptMask *)OSPhysicalToCached(0x00C8));
if (unmasked) {
for (prio = InterruptPrioTable;; ++prio) {
if (unmasked & *prio) {
interrupt = (__OSInterrupt)__cntlzw(unmasked & *prio);
break;
}
}
handler = __OSGetInterruptHandler(interrupt);
if (handler) {
if (__OS_INTERRUPT_MEM_ADDRESS < interrupt) {
__OSLastInterrupt = interrupt;
__OSLastInterruptTime = OSGetTime();
__OSLastInterruptSrr0 = context->srr0;
}
OSDisableScheduler();
handler(interrupt, context);
OSEnableScheduler();
__OSReschedule();
OSLoadContext(context);
}
}
OSLoadContext(context);
}
static asm void ExternalInterruptHandler(register __OSException exception, register OSContext *context)
{
#pragma unused(exception)
// clang-format off
nofralloc
OS_EXCEPTION_SAVE_GPRS(context)
stwu r1, -8(r1)
b __OSDispatchInterrupt
// clang-format on
}

504
src/dolphin/os/OSLink.c Normal file
View file

@ -0,0 +1,504 @@
#include "dolphin/os.h"
#define SHN_UNDEF 0
#define SHN_LORESERVE 0xff00
#define SHN_LOPROC 0xff00
#define SHN_HIPROC 0xff1f
#define SHN_ABS 0xfff1
#define SHN_COMMON 0xfff2
#define SHN_HIRESERVE 0xffff
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
// Name Value Field Calculation
#define R_PPC_NONE 0 // none none
#define R_PPC_ADDR32 1 // word32 S + A
#define R_PPC_ADDR24 2 // low24* (S + A) >> 2
#define R_PPC_ADDR16 3 // half16* S + A
#define R_PPC_ADDR16_LO 4 // half16 #lo(S + A)
#define R_PPC_ADDR16_HI 5 // half16 #hi(S + A)
#define R_PPC_ADDR16_HA 6 // half16 #ha(S + A)
#define R_PPC_ADDR14 7 // low14* (S + A) >> 2
#define R_PPC_ADDR14_BRTAKEN 8 // low14* (S + A) >> 2
#define R_PPC_ADDR14_BRNTAKEN 9 // low14* (S + A) >> 2
#define R_PPC_REL24 10 // low24* (S + A - P) >> 2
#define R_PPC_REL14 11 // low14* (S + A - P) >> 2
#define R_PPC_REL14_BRTAKEN 12 // low14* (S + A - P) >> 2
#define R_PPC_REL14_BRNTAKEN 13 // low14* (S + A - P) >> 2
#define R_PPC_GOT16 14 // half16* G + A
#define R_PPC_GOT16_LO 15 // half16 #lo(G + A)
#define R_PPC_GOT16_HI 16 // half16 #hi(G + A)
#define R_PPC_GOT16_HA 17 // half16 #ha(G + A)
#define R_PPC_PLTREL24 18 // low24* (L + A - P) >> 2
#define R_PPC_COPY 19 // none none
#define R_PPC_GLOB_DAT 20 // word32 S + A
#define R_PPC_JMP_SLOT 21 // none
#define R_PPC_RELATIVE 22 // word32 B + A
#define R_PPC_LOCAL24PC 23 // low24*
#define R_PPC_UADDR32 24 // word32 S + A
#define R_PPC_UADDR16 25 // half16* S + A
#define R_PPC_REL32 26 // word32 S + A - P
#define R_PPC_PLT32 27 // word32 L + A
#define R_PPC_PLTREL32 28 // word32 L + A - P
#define R_PPC_PLT16_LO 29 // half16 #lo(L + A)
#define R_PPL_PLT16_HI 30 // half16 #hi(L + A)
#define R_PPC_PLT16_HA 31 // half16 #ha(L + A)
#define R_PPC_SDAREL16 32 // half16* S + A - _SDA_BASE_
#define R_PPC_SECTOFF 33 // half16* R + A
#define R_PPC_SECTOFF_LO 34 // half16 #lo(R + A)
#define R_PPC_SECTOFF_HI 35 // half16 #hi(R + A)
#define R_PPC_SECTOFF_HA 36 // half16 #ha(R + A)
#define R_PPC_ADDR30 37 // word30 (S + A - P) >> 2
#define R_PPC_EMB_NADDR32 101 // uword32 N (A - S)
#define R_PPC_EMB_NADDR16 102 // uhalf16 Y (A - S)
#define R_PPC_EMB_NADDR16_LO 103 // uhalf16 N #lo(A - S)
#define R_PPC_EMB_NADDR16_HI 104 // uhalf16 N #hi(A - S)
#define R_PPC_EMB_NADDR16_HA 105 // uhalf16 N #ha(A - S)
#define R_PPC_EMB_SDAI16 106 // uhalf16 Y T
#define R_PPC_EMB_SDA2I16 107 // uhalf16 Y U
#define R_PPC_EMB_SDA2REL 108 // uhalf16 Y S + A - _SDA2_BASE_
#define R_PPC_EMB_SDA21 109 // ulow21 N
#define R_PPC_EMB_MRKREF 110 // none N
#define R_PPC_EMB_RELSEC16 111 // uhalf16 Y V + A
#define R_PPC_EMB_RELST_LO 112 // uhalf16 N #lo(W + A)
#define R_PPC_EMB_RELST_HI 113 // uhalf16 N #hi(W + A)
#define R_PPC_EMB_RELST_HA 114 // uhalf16 N #ha(W + A)
#define R_PPC_EMB_BIT_FLD 115 // uword32 Y
#define R_PPC_EMB_RELSDA 116 // uhalf16 Y
OSModuleQueue __OSModuleInfoList : (OS_BASE_CACHED | 0x30C8);
const void *__OSStringTable : (OS_BASE_CACHED | 0x30D0);
#pragma dont_inline on
__declspec(weak) void OSNotifyLink(void) { }
__declspec(weak) void OSNotifyUnlink(void) { }
#pragma dont_inline reset
#define EnqueueTail(queue, moduleInfo, link) \
do { \
OSModuleInfo *__prev; \
\
__prev = (queue)->tail; \
if (__prev == NULL) \
(queue)->head = (moduleInfo); \
else \
__prev->link.next = (moduleInfo); \
(moduleInfo)->link.prev = __prev; \
(moduleInfo)->link.next = NULL; \
(queue)->tail = (moduleInfo); \
} while (0)
#define DequeueItem(queue, moduleInfo, link) \
do { \
OSModuleInfo *__next; \
OSModuleInfo *__prev; \
\
__next = (moduleInfo)->link.next; \
__prev = (moduleInfo)->link.prev; \
\
if (__next == NULL) \
(queue)->tail = __prev; \
else \
__next->link.prev = __prev; \
\
if (__prev == NULL) \
(queue)->head = __next; \
else \
__prev->link.next = __next; \
} while (0)
void OSSetStringTable(const void *stringTable)
{
__OSStringTable = stringTable;
}
static BOOL Relocate(OSModuleHeader *newModule, OSModuleHeader *module)
{
OSModuleID idNew;
OSImportInfo *imp;
OSRel *rel;
OSSectionInfo *si;
OSSectionInfo *siFlush;
u32 *p;
u32 offset;
u32 x;
idNew = newModule ? newModule->info.id : 0;
for (imp = (OSImportInfo *)module->impOffset; imp < (OSImportInfo *)(module->impOffset + module->impSize); imp++) {
if (imp->id == idNew) {
goto Found;
}
}
return FALSE;
Found:
siFlush = 0;
for (rel = (OSRel *)imp->offset; rel->type != R_DOLPHIN_END; rel++) {
(u8 *)p += rel->offset;
if (idNew) {
si = &OSGetSectionInfo(newModule)[rel->section];
offset = OS_SECTIONINFO_OFFSET(si->offset);
}
else {
offset = 0;
}
switch (rel->type) {
case R_PPC_NONE:
break;
case R_PPC_ADDR32:
x = offset + rel->addend;
*p = x;
break;
case R_PPC_ADDR24:
x = offset + rel->addend;
*p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
break;
case R_PPC_ADDR16:
x = offset + rel->addend;
*(u16 *)p = (u16)(x & 0xffff);
break;
case R_PPC_ADDR16_LO:
x = offset + rel->addend;
*(u16 *)p = (u16)(x & 0xffff);
break;
case R_PPC_ADDR16_HI:
x = offset + rel->addend;
*(u16 *)p = (u16)(((x >> 16) & 0xffff));
break;
case R_PPC_ADDR16_HA:
x = offset + rel->addend;
*(u16 *)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff);
break;
case R_PPC_REL24:
x = offset + rel->addend - (u32)p;
*p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
break;
case R_DOLPHIN_NOP:
break;
case R_DOLPHIN_SECTION:
si = &OSGetSectionInfo(module)[rel->section];
p = (u32 *)OS_SECTIONINFO_OFFSET(si->offset);
if (siFlush) {
offset = OS_SECTIONINFO_OFFSET(siFlush->offset);
DCFlushRange((void *)offset, siFlush->size);
ICInvalidateRange((void *)offset, siFlush->size);
}
siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0;
break;
default:
OSReport("OSLink: unknown relocation type %3d\n", rel->type);
break;
}
}
if (siFlush) {
offset = OS_SECTIONINFO_OFFSET(siFlush->offset);
DCFlushRange((void *)offset, siFlush->size);
ICInvalidateRange((void *)offset, siFlush->size);
}
return TRUE;
}
#if OS_MODULE_VERSION >= 3
static BOOL Link(OSModuleInfo *newModule, void *bss, BOOL fixed)
{
u32 i;
OSSectionInfo *si;
OSModuleHeader *moduleHeader;
OSModuleInfo *moduleInfo;
OSImportInfo *imp;
moduleHeader = (OSModuleHeader *)newModule;
moduleHeader->bssSection = 0;
if (OS_MODULE_VERSION < newModule->version
|| 2 <= newModule->version
&& (moduleHeader->align && (u32)newModule % moduleHeader->align != 0
|| moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0)) {
return FALSE;
}
EnqueueTail(&__OSModuleInfoList, newModule, link);
newModule->sectionInfoOffset += (u32)moduleHeader;
moduleHeader->relOffset += (u32)moduleHeader;
moduleHeader->impOffset += (u32)moduleHeader;
if (3 <= newModule->version) {
moduleHeader->fixSize += (u32)moduleHeader;
}
for (i = 1; i < newModule->numSections; i++) {
si = &OSGetSectionInfo(newModule)[i];
if (si->offset != 0) {
si->offset += (u32)moduleHeader;
}
else if (si->size != 0) {
moduleHeader->bssSection = (u8)i;
si->offset = (u32)bss;
bss = (void *)((u32)bss + si->size);
}
}
for (imp = (OSImportInfo *)moduleHeader->impOffset; imp < (OSImportInfo *)(moduleHeader->impOffset + moduleHeader->impSize); imp++) {
imp->offset += (u32)moduleHeader;
}
if (moduleHeader->prologSection != SHN_UNDEF) {
moduleHeader->prolog += OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->prologSection].offset);
}
if (moduleHeader->epilogSection != SHN_UNDEF) {
moduleHeader->epilog += OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->epilogSection].offset);
}
if (moduleHeader->unresolvedSection != SHN_UNDEF) {
moduleHeader->unresolved += OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->unresolvedSection].offset);
}
if (__OSStringTable) {
newModule->nameOffset += (u32)__OSStringTable;
}
Relocate(0, moduleHeader);
for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
Relocate(moduleHeader, (OSModuleHeader *)moduleInfo);
if (moduleInfo != newModule) {
Relocate((OSModuleHeader *)moduleInfo, moduleHeader);
}
}
if (fixed) {
for (imp = (OSImportInfo *)moduleHeader->impOffset; imp < (OSImportInfo *)(moduleHeader->impOffset + moduleHeader->impSize); imp++) {
if (imp->id == 0 || imp->id == newModule->id) {
moduleHeader->impSize = (u32)((u8 *)imp - (u8 *)moduleHeader->impOffset);
break;
}
}
}
memset(bss, 0, moduleHeader->bssSize);
OSNotifyLink(newModule);
return TRUE;
}
BOOL OSLink(OSModuleInfo *newModule, void *bss)
{
return Link(newModule, bss, FALSE);
}
BOOL OSLinkFixed(OSModuleInfo *newModule, void *bss)
{
if (OS_MODULE_VERSION < newModule->version || newModule->version < 3) {
return FALSE;
}
return Link(newModule, bss, TRUE);
}
#else
BOOL OSLink(OSModuleInfo *newModule, void *bss)
{
u32 i;
OSSectionInfo *si;
OSModuleHeader *moduleHeader;
OSModuleInfo *moduleInfo;
OSImportInfo *imp;
moduleHeader = (OSModuleHeader *)newModule;
if (OS_MODULE_VERSION < newModule->version
|| 2 <= newModule->version
&& (moduleHeader->align && (u32)newModule % moduleHeader->align != 0
|| moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0)) {
return FALSE;
}
EnqueueTail(&__OSModuleInfoList, newModule, link);
memset(bss, 0, moduleHeader->bssSize);
newModule->sectionInfoOffset += (u32)moduleHeader;
moduleHeader->relOffset += (u32)moduleHeader;
moduleHeader->impOffset += (u32)moduleHeader;
for (i = 0; i < newModule->numSections; i++) {
si = &OSGetSectionInfo(newModule)[i];
if (si->offset != 0) {
si->offset += (u32)moduleHeader;
}
else if (si->size != 0) {
si->offset = (u32)bss;
bss = (void *)((u32)bss + si->size);
}
}
for (imp = (OSImportInfo *)moduleHeader->impOffset; imp < (OSImportInfo *)(moduleHeader->impOffset + moduleHeader->impSize); imp++) {
imp->offset += (u32)moduleHeader;
}
if (moduleHeader->prologSection != SHN_UNDEF) {
moduleHeader->prolog += OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->prologSection].offset);
}
if (moduleHeader->epilogSection != SHN_UNDEF) {
moduleHeader->epilog += OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->epilogSection].offset);
}
if (moduleHeader->unresolvedSection != SHN_UNDEF) {
moduleHeader->unresolved += OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->unresolvedSection].offset);
}
if (__OSStringTable) {
newModule->nameOffset += (u32)__OSStringTable;
}
Relocate(0, moduleHeader);
for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
Relocate(moduleHeader, (OSModuleHeader *)moduleInfo);
if (moduleInfo != newModule) {
Relocate((OSModuleHeader *)moduleInfo, moduleHeader);
}
}
OSNotifyLink();
return TRUE;
}
#endif
static BOOL Undo(OSModuleHeader *newModule, OSModuleHeader *module)
{
OSModuleID idNew;
OSImportInfo *imp;
OSRel *rel;
OSSectionInfo *si;
OSSectionInfo *siFlush;
u32 *p;
u32 offset;
u32 x;
idNew = newModule->info.id;
for (imp = (OSImportInfo *)module->impOffset; imp < (OSImportInfo *)(module->impOffset + module->impSize); imp++) {
if (imp->id == idNew) {
goto Found;
}
}
return FALSE;
Found:
siFlush = 0;
for (rel = (OSRel *)imp->offset; rel->type != R_DOLPHIN_END; rel++) {
(u8 *)p += rel->offset;
si = &OSGetSectionInfo(newModule)[rel->section];
offset = OS_SECTIONINFO_OFFSET(si->offset);
x = 0;
switch (rel->type) {
case R_PPC_NONE:
break;
case R_PPC_ADDR32:
*p = x;
break;
case R_PPC_ADDR24:
*p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
break;
case R_PPC_ADDR16:
*(u16 *)p = (u16)(x & 0xffff);
break;
case R_PPC_ADDR16_LO:
*(u16 *)p = (u16)(x & 0xffff);
break;
case R_PPC_ADDR16_HI:
*(u16 *)p = (u16)(((x >> 16) & 0xffff));
break;
case R_PPC_ADDR16_HA:
*(u16 *)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff);
break;
case R_PPC_REL24:
if (module->unresolvedSection != SHN_UNDEF) {
x = (u32)module->unresolved - (u32)p;
}
*p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
break;
case R_DOLPHIN_NOP:
break;
case R_DOLPHIN_SECTION:
si = &OSGetSectionInfo(module)[rel->section];
p = (u32 *)OS_SECTIONINFO_OFFSET(si->offset);
if (siFlush) {
offset = OS_SECTIONINFO_OFFSET(siFlush->offset);
DCFlushRange((void *)offset, siFlush->size);
ICInvalidateRange((void *)offset, siFlush->size);
}
siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0;
break;
default:
OSReport("OSUnlink: unknown relocation type %3d\n", rel->type);
break;
}
}
if (siFlush) {
offset = OS_SECTIONINFO_OFFSET(siFlush->offset);
DCFlushRange((void *)offset, siFlush->size);
ICInvalidateRange((void *)offset, siFlush->size);
}
return TRUE;
}
BOOL OSUnlink(OSModuleInfo *oldModule)
{
OSModuleHeader *moduleHeader;
OSModuleInfo *moduleInfo;
moduleHeader = (OSModuleHeader *)oldModule;
DequeueItem(&__OSModuleInfoList, oldModule, link);
for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
Undo(moduleHeader, (OSModuleHeader *)moduleInfo);
}
OSNotifyUnlink();
return TRUE;
}
void __OSModuleInit(void)
{
__OSModuleInfoList.head = __OSModuleInfoList.tail = 0;
__OSStringTable = 0;
}
OSModuleInfo *OSSearchModule(void *ptr, u32 *section, u32 *offset)
{
OSModuleInfo *moduleInfo;
OSSectionInfo *sectionInfo;
u32 i;
u32 baseSection;
if (ptr == NULL) {
return NULL;
}
for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
sectionInfo = OSGetSectionInfo(moduleInfo);
for (i = 0; i < moduleInfo->numSections; ++i) {
if (sectionInfo->size) {
baseSection = OS_SECTIONINFO_OFFSET(sectionInfo->offset);
if (baseSection <= (u32)ptr && (u32)ptr < baseSection + sectionInfo->size) {
if (section) {
*section = i;
}
if (offset) {
*offset = (u32)ptr - baseSection;
}
return moduleInfo;
}
}
sectionInfo++;
}
}
return NULL;
}

230
src/dolphin/os/OSMemory.c Normal file
View file

@ -0,0 +1,230 @@
#include <dolphin/os.h>
#include <dolphin/hw_regs.h>
#define TRUNC(n, a) (((u32)(n)) & ~((a)-1))
#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1))
extern OSErrorHandler __OSErrorTable[16];
static BOOL OnReset(BOOL final);
static OSResetFunctionInfo ResetFunctionInfo = {
OnReset,
127,
};
u32 OSGetPhysicalMemSize()
{
return *(u32 *)(OSPhysicalToCached(0x0028));
}
u32 OSGetConsoleSimulatedMemSize()
{
return *(u32 *)(OSPhysicalToCached(0x00F0));
}
static BOOL OnReset(BOOL final)
{
if (final != FALSE) {
__MEMRegs[8] = 0xFF;
__OSMaskInterrupts(0xf0000000);
}
return TRUE;
}
static void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext *context)
{
u32 addr;
u32 cause;
cause = __MEMRegs[0xf];
addr = (((u32)__MEMRegs[0x12] & 0x3ff) << 16) | __MEMRegs[0x11];
__MEMRegs[0x10] = 0;
if (__OSErrorTable[OS_ERROR_PROTECTION]) {
__OSErrorTable[OS_ERROR_PROTECTION](OS_ERROR_PROTECTION, context, cause, addr);
return;
}
__OSUnhandledException(OS_ERROR_PROTECTION, context, cause, addr);
}
void OSProtectRange(u32 chan, void *addr, u32 nBytes, u32 control)
{
BOOL enabled;
u32 start;
u32 end;
u16 reg;
if (4 <= chan) {
return;
}
control &= OS_PROTECT_CONTROL_RDWR;
end = (u32)addr + nBytes;
start = TRUNC(addr, 1u << 10);
end = ROUND(end, 1u << 10);
DCFlushRange((void *)start, end - start);
enabled = OSDisableInterrupts();
__OSMaskInterrupts(OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0 + chan));
__MEMRegs[0 + 2 * chan] = (u16)(start >> 10);
__MEMRegs[1 + 2 * chan] = (u16)(end >> 10);
reg = __MEMRegs[8];
reg &= ~(OS_PROTECT_CONTROL_RDWR << 2 * chan);
reg |= control << 2 * chan;
__MEMRegs[8] = reg;
if (control != OS_PROTECT_CONTROL_RDWR) {
__OSUnmaskInterrupts(OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0 + chan));
}
OSRestoreInterrupts(enabled);
}
asm void Config24MB()
{
// clang-format off
nofralloc
addi r7,r0,0
addis r4,r0,0x00000002@ha
addi r4,r4,0x00000002@l
addis r3,r0,0x800001ff@ha
addi r3,r3,0x800001ff@l
addis r6,r0,0x01000002@ha
addi r6,r6,0x01000002@l
addis r5,r0,0x810000ff@ha
addi r5,r5,0x810000ff@l
isync
mtspr dbat0u,r7
mtspr dbat0l,r4
mtspr dbat0u,r3
isync
mtspr ibat0u,r7
mtspr ibat0l,r4
mtspr ibat0u,r3
isync
mtspr dbat2u,r7
mtspr dbat2l,r6
mtspr dbat2u,r5
isync
mtspr ibat2u,r7
mtspr ibat2l,r6
mtspr ibat2u,r5
isync
mfmsr r3
ori r3, r3, 0x30
mtsrr1 r3
mflr r3
mtsrr0 r3
rfi
// clang-format on
}
asm void Config48MB()
{
// clang-format off
nofralloc
addi r7,r0,0x0000
addis r4,r0,0x00000002@ha
addi r4,r4,0x00000002@l
addis r3,r0,0x800003ff@ha
addi r3,r3,0x800003ff@l
addis r6,r0,0x02000002@ha
addi r6,r6,0x02000002@l
addis r5,r0,0x820001ff@ha
addi r5,r5,0x820001ff@l
isync
mtspr dbat0u,r7
mtspr dbat0l,r4
mtspr dbat0u,r3
isync
mtspr ibat0u,r7
mtspr ibat0l,r4
mtspr ibat0u,r3
isync
mtspr dbat2u,r7
mtspr dbat2l,r6
mtspr dbat2u,r5
isync
mtspr ibat2u,r7
mtspr ibat2l,r6
mtspr ibat2u,r5
isync
mfmsr r3
ori r3, r3, 0x30
mtsrr1 r3
mflr r3
mtsrr0 r3
rfi
// clang-format on
}
asm void RealMode(register u32 addr)
{
// clang-format off
nofralloc
clrlwi r3, r3, 2
mtsrr0 r3
mfmsr r3
rlwinm r3, r3, 0, 28, 25
mtsrr1 r3
rfi
// clang-format on
}
void __OSInitMemoryProtection()
{
u32 padding[8];
u32 simulatedSize;
BOOL enabled;
simulatedSize = OSGetConsoleSimulatedMemSize();
enabled = OSDisableInterrupts();
if (simulatedSize <= 0x1800000) {
RealMode((u32)&Config24MB);
}
else if (simulatedSize <= 0x3000000) {
RealMode((u32)&Config48MB);
}
__MEMRegs[16] = 0;
__MEMRegs[8] = 0xFF;
__OSMaskInterrupts(OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | OS_INTERRUPTMASK_MEM_3);
__OSSetInterruptHandler(__OS_INTERRUPT_MEM_0, MEMIntrruptHandler);
__OSSetInterruptHandler(__OS_INTERRUPT_MEM_1, MEMIntrruptHandler);
__OSSetInterruptHandler(__OS_INTERRUPT_MEM_2, MEMIntrruptHandler);
__OSSetInterruptHandler(__OS_INTERRUPT_MEM_3, MEMIntrruptHandler);
__OSSetInterruptHandler(__OS_INTERRUPT_MEM_ADDRESS, MEMIntrruptHandler);
OSRegisterResetFunction(&ResetFunctionInfo);
if (OSGetConsoleSimulatedMemSize() < OSGetPhysicalMemSize() && OSGetConsoleSimulatedMemSize() == 0x1800000) {
__MEMRegs[20] = 2;
}
__OSUnmaskInterrupts(OS_INTERRUPTMASK_MEM_ADDRESS);
OSRestoreInterrupts(enabled);
}

View file

@ -0,0 +1,91 @@
#include <dolphin/os.h>
void OSInitMessageQueue(OSMessageQueue *mq, OSMessage *msgArray, s32 msgCount)
{
OSInitThreadQueue(&mq->queueSend);
OSInitThreadQueue(&mq->queueReceive);
mq->msgArray = msgArray;
mq->msgCount = msgCount;
mq->firstIndex = 0;
mq->usedCount = 0;
}
BOOL OSSendMessage(OSMessageQueue *mq, OSMessage msg, s32 flags)
{
BOOL enabled;
s32 lastIndex;
enabled = OSDisableInterrupts();
while (mq->msgCount <= mq->usedCount) {
if (!(flags & OS_MESSAGE_BLOCK)) {
OSRestoreInterrupts(enabled);
return FALSE;
}
else {
OSSleepThread(&mq->queueSend);
}
}
lastIndex = (mq->firstIndex + mq->usedCount) % mq->msgCount;
mq->msgArray[lastIndex] = msg;
mq->usedCount++;
OSWakeupThread(&mq->queueReceive);
OSRestoreInterrupts(enabled);
return TRUE;
}
BOOL OSReceiveMessage(OSMessageQueue *mq, OSMessage *msg, s32 flags)
{
BOOL enabled;
enabled = OSDisableInterrupts();
while (mq->usedCount == 0) {
if (!(flags & OS_MESSAGE_BLOCK)) {
OSRestoreInterrupts(enabled);
return FALSE;
}
else {
OSSleepThread(&mq->queueReceive);
}
}
if (msg != NULL) {
*msg = mq->msgArray[mq->firstIndex];
}
mq->firstIndex = (mq->firstIndex + 1) % mq->msgCount;
mq->usedCount--;
OSWakeupThread(&mq->queueSend);
OSRestoreInterrupts(enabled);
return TRUE;
}
BOOL OSJamMessage(OSMessageQueue *mq, OSMessage msg, s32 flags)
{
BOOL enabled;
enabled = OSDisableInterrupts();
while (mq->msgCount <= mq->usedCount) {
if (!(flags & OS_MESSAGE_BLOCK)) {
OSRestoreInterrupts(enabled);
return FALSE;
}
else {
OSSleepThread(&mq->queueSend);
}
}
mq->firstIndex = (mq->firstIndex + mq->msgCount - 1) % mq->msgCount;
mq->msgArray[mq->firstIndex] = msg;
mq->usedCount++;
OSWakeupThread(&mq->queueReceive);
OSRestoreInterrupts(enabled);
return TRUE;
}

244
src/dolphin/os/OSMutex.c Normal file
View file

@ -0,0 +1,244 @@
#include "dolphin/os.h"
#define PushTail(queue, mutex, link) \
do { \
OSMutex *__prev; \
\
__prev = (queue)->tail; \
if (__prev == NULL) \
(queue)->head = (mutex); \
else \
__prev->link.next = (mutex); \
(mutex)->link.prev = __prev; \
(mutex)->link.next = NULL; \
(queue)->tail = (mutex); \
} while (0)
#define PopHead(queue, mutex, link) \
do { \
OSMutex *__next; \
\
(mutex) = (queue)->head; \
__next = (mutex)->link.next; \
if (__next == NULL) \
(queue)->tail = NULL; \
else \
__next->link.prev = NULL; \
(queue)->head = __next; \
} while (0)
#define PopItem(queue, mutex, link) \
do { \
OSMutex *__next; \
OSMutex *__prev; \
\
__next = (mutex)->link.next; \
__prev = (mutex)->link.prev; \
\
if (__next == NULL) \
(queue)->tail = __prev; \
else \
__next->link.prev = __prev; \
\
if (__prev == NULL) \
(queue)->head = __next; \
else \
__prev->link.next = __next; \
} while (0)
void OSInitMutex(OSMutex *mutex)
{
OSInitThreadQueue(&mutex->queue);
mutex->thread = 0;
mutex->count = 0;
}
void OSLockMutex(OSMutex *mutex)
{
BOOL enabled = OSDisableInterrupts();
OSThread *currentThread = OSGetCurrentThread();
OSThread *ownerThread;
while (TRUE) {
ownerThread = ((OSMutex *)mutex)->thread;
if (ownerThread == 0) {
mutex->thread = currentThread;
mutex->count++;
PushTail(&currentThread->queueMutex, mutex, link);
break;
}
else if (ownerThread == currentThread) {
mutex->count++;
break;
}
else {
currentThread->mutex = mutex;
__OSPromoteThread(mutex->thread, currentThread->priority);
OSSleepThread(&mutex->queue);
currentThread->mutex = 0;
}
}
OSRestoreInterrupts(enabled);
}
void OSUnlockMutex(OSMutex *mutex)
{
BOOL enabled = OSDisableInterrupts();
OSThread *currentThread = OSGetCurrentThread();
if (mutex->thread == currentThread && --mutex->count == 0) {
PopItem(&currentThread->queueMutex, mutex, link);
mutex->thread = NULL;
if (currentThread->priority < currentThread->base) {
currentThread->priority = __OSGetEffectivePriority(currentThread);
}
OSWakeupThread(&mutex->queue);
}
OSRestoreInterrupts(enabled);
}
void __OSUnlockAllMutex(OSThread *thread)
{
OSMutex *mutex;
while (thread->queueMutex.head) {
PopHead(&thread->queueMutex, mutex, link);
mutex->count = 0;
mutex->thread = NULL;
OSWakeupThread(&mutex->queue);
}
}
BOOL OSTryLockMutex(OSMutex *mutex)
{
BOOL enabled = OSDisableInterrupts();
OSThread *currentThread = OSGetCurrentThread();
BOOL locked;
if (mutex->thread == 0) {
mutex->thread = currentThread;
mutex->count++;
PushTail(&currentThread->queueMutex, mutex, link);
locked = TRUE;
}
else if (mutex->thread == currentThread) {
mutex->count++;
locked = TRUE;
}
else {
locked = FALSE;
}
OSRestoreInterrupts(enabled);
return locked;
}
void OSInitCond(OSCond *cond)
{
OSInitThreadQueue(&cond->queue);
}
void OSWaitCond(OSCond *cond, OSMutex *mutex)
{
BOOL enabled = OSDisableInterrupts();
OSThread *currentThread = OSGetCurrentThread();
s32 count;
if (mutex->thread == currentThread) {
count = mutex->count;
mutex->count = 0;
PopItem(&currentThread->queueMutex, mutex, link);
mutex->thread = NULL;
if (currentThread->priority < currentThread->base) {
currentThread->priority = __OSGetEffectivePriority(currentThread);
}
OSDisableScheduler();
OSWakeupThread(&mutex->queue);
OSEnableScheduler();
OSSleepThread(&cond->queue);
OSLockMutex(mutex);
mutex->count = count;
}
OSRestoreInterrupts(enabled);
}
void OSSignalCond(OSCond *cond)
{
OSWakeupThread(&cond->queue);
}
static BOOL IsMember(OSMutexQueue *queue, OSMutex *mutex)
{
OSMutex *member;
for (member = queue->head; member; member = member->link.next) {
if (mutex == member)
return TRUE;
}
return FALSE;
}
BOOL __OSCheckMutex(OSMutex *mutex)
{
OSThread *thread;
OSThreadQueue *queue;
OSPriority priority = 0;
queue = &mutex->queue;
if (!(queue->head == NULL || queue->head->link.prev == NULL))
return FALSE;
if (!(queue->tail == NULL || queue->tail->link.next == NULL))
return FALSE;
for (thread = queue->head; thread; thread = thread->link.next) {
if (!(thread->link.next == NULL || thread == thread->link.next->link.prev))
return FALSE;
if (!(thread->link.prev == NULL || thread == thread->link.prev->link.next))
return FALSE;
if (thread->state != OS_THREAD_STATE_WAITING)
return FALSE;
if (thread->priority < priority)
return FALSE;
priority = thread->priority;
}
if (mutex->thread) {
if (mutex->count <= 0)
return FALSE;
}
else {
if (0 != mutex->count)
return FALSE;
}
return TRUE;
}
BOOL __OSCheckDeadLock(OSThread *thread)
{
OSMutex *mutex;
mutex = thread->mutex;
while (mutex && mutex->thread) {
if (mutex->thread == thread)
return TRUE;
mutex = mutex->thread->mutex;
}
return FALSE;
}
BOOL __OSCheckMutexes(OSThread *thread)
{
OSMutex *mutex;
for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) {
if (mutex->thread != thread)
return FALSE;
if (!__OSCheckMutex(mutex))
return FALSE;
}
return TRUE;
}

94
src/dolphin/os/OSReboot.c Normal file
View file

@ -0,0 +1,94 @@
#include <dolphin/dvd.h>
#include <dolphin/os.h>
#include <dolphin/os/OSBootInfo.h>
#include <dolphin/os/OSContext.h>
#include <dolphin/os/OSInterrupt.h>
typedef struct ApploaderHeader {
// total size: 0x20
char date[16]; // offset 0x0, size 0x10
u32 entry; // offset 0x10, size 0x4
u32 size; // offset 0x14, size 0x4
u32 rebootSize; // offset 0x18, size 0x4
u32 reserved2; // offset 0x1C, size 0x4
} ApploaderHeader;
struct {
// total size: 0x1C
int valid; // offset 0x0, size 0x4
unsigned long restartCode; // offset 0x4, size 0x4
unsigned long bootDol; // offset 0x8, size 0x4
void *regionStart; // offset 0xC, size 0x4
void *regionEnd; // offset 0x10, size 0x4
int argsUseDefault; // offset 0x14, size 0x4
void *argsAddr; // offset 0x18, size 0x4
} __OSRebootParams; // size: 0x1C, address: 0x0
static ApploaderHeader Header;
extern void *__OSSavedRegionStart;
extern void *__OSSavedRegionEnd;
static void *SaveStart = NULL;
static void *SaveEnd = NULL;
volatile u8 DAT_800030e2 : 0x800030e2;
extern u32 BOOT_REGION_START AT_ADDRESS(0x812FDFF0); //(*(u32 *)0x812fdff0)
extern u32 BOOT_REGION_END AT_ADDRESS(0x812FDFEC); //(*(u32 *)0x812fdfec)
extern u32 UNK_HOT_RESET1 AT_ADDRESS(0x817ffff8);
extern u32 UNK_HOT_RESET2 AT_ADDRESS(0x817ffffc);
// extern u32 OS_RESET_CODE AT_ADDRESS(0x800030F0);
// extern u8 OS_REBOOT_BOOL AT_ADDRESS(0x800030E2); // unknown function, set to true by __OSReboot
extern u32 __OSIsGcam;
static BOOL Prepared = FALSE;
extern void __DVDPrepareResetAsync(DVDCBCallback callback);
extern BOOL DVDCheckDisk(void);
extern BOOL DVDReadAbsAsyncForBS(DVDCommandBlock *block, void *addr, s32 length, s32 offset, DVDCBCallback callback);
void Run(register u32 addr)
{
OSDisableInterrupts();
ICFlashInvalidate();
// clang-format off
asm {
sync
isync
mtlr addr
blr
}
// clang-format on
}
static void Callback()
{
Prepared = TRUE;
}
void ReadApploader(OSTime time1) { }
void __OSReboot(u32 resetCode, u32 bootDol)
{
// TODO
}
void OSSetSaveRegion(void *start, void *end)
{
SaveStart = start;
SaveEnd = end;
}
void OSGetSaveRegion(void **start, void **end)
{
*start = SaveStart;
*end = SaveEnd;
}
void OSGetSavedRegion(void **start, void **end)
{
*start = __OSSavedRegionStart;
*end = __OSSavedRegionEnd;
}

203
src/dolphin/os/OSReset.c Normal file
View file

@ -0,0 +1,203 @@
#include <dolphin/OSRtcPriv.h>
#include <dolphin/hw_regs.h>
#include <dolphin/os.h>
#include <dolphin/os/osPriv.h>
#include <dolphin/vi.h>
#include "string.h"
volatile u8 DAT_800030e2 : 0x800030e2;
typedef struct Unk {
u8 pad[0x24];
u32 resetCode;
} Unk;
volatile Unk DAT_cc003000 : 0xcc003000;
typedef struct Unk2 {
u16 _0;
u16 _2;
} Unk2;
volatile Unk2 DAT_cc002000 : 0xcc002000;
typedef struct OSResetQueue {
OSResetFunctionInfo *first;
OSResetFunctionInfo *last;
} OSResetQueue;
OSResetQueue ResetFunctionQueue;
void OSRegisterResetFunction(OSResetFunctionInfo *func)
{
OSResetFunctionInfo *tmp;
OSResetFunctionInfo *iter;
for (iter = ResetFunctionQueue.first; iter && iter->priority <= func->priority; iter = iter->next)
;
if (iter == NULL) {
tmp = ResetFunctionQueue.last;
if (tmp == NULL) {
ResetFunctionQueue.first = func;
}
else {
tmp->next = func;
}
func->prev = tmp;
func->next = NULL;
ResetFunctionQueue.last = func;
return;
}
func->next = iter;
tmp = iter->prev;
iter->prev = func;
func->prev = tmp;
if (tmp == NULL) {
ResetFunctionQueue.first = func;
return;
}
tmp->next = func;
}
BOOL __OSCallResetFunctions(u32 arg0)
{
OSResetFunctionInfo *iter;
s32 retCode = 0;
for (iter = ResetFunctionQueue.first; iter != NULL; iter = iter->next) {
retCode |= !iter->func(arg0);
}
retCode |= !__OSSyncSram();
if (retCode) {
return 0;
}
return 1;
}
asm void Reset(register s32 resetCode)
{
// clang-format off
nofralloc
b lbl_8038315C
lbl_80383140:
mfspr r8, HID0
ori r8, r8, 8
mtspr HID0, r8
isync
sync
nop
b lbl_80383160
lbl_8038315C:
b lbl_8038317C
lbl_80383160:
mftb r5, 268
lbl_80383164:
mftb r6, 268
subf r7, r5, r6
cmplwi r7, 0x1124
blt lbl_80383164
nop
b lbl_80383180
lbl_8038317C:
b lbl_8038319C
lbl_80383180:
lis r8, 0xCC003000@h
ori r8, r8, 0xCC003000@l
li r4, 3
stw r4, 0x24(r8)
stw r3, 0x24(r8)
nop
b lbl_803831A0
lbl_8038319C:
b lbl_803831A8
lbl_803831A0:
nop
b lbl_803831A0
lbl_803831A8:
b lbl_80383140
// clang-format on
}
OSThreadQueue __OSActiveThreadQueue : (OS_BASE_CACHED | 0x00DC);
static void KillThreads(void)
{
OSThread *thread;
OSThread *next;
for (thread = __OSActiveThreadQueue.head; thread; thread = next) {
next = thread->linkActive.next;
switch (thread->state) {
case 1:
case 4:
OSCancelThread(thread);
break;
default:
break;
}
}
}
void __OSDoHotReset(s32 arg0)
{
OSDisableInterrupts();
__VIRegs[1] = 0;
ICFlashInvalidate();
Reset(arg0 * 8);
}
void OSResetSystem(int reset, u32 resetCode, BOOL forceMenu)
{
BOOL rc;
BOOL disableRecalibration;
u32 unk[3];
OSDisableScheduler();
__OSStopAudioSystem();
if (reset == OS_RESET_SHUTDOWN) {
disableRecalibration = __PADDisableRecalibration(TRUE);
}
while (!__OSCallResetFunctions(FALSE))
;
if (reset == OS_RESET_HOTRESET && forceMenu) {
OSSram *sram;
sram = __OSLockSram();
sram->flags |= 0x40;
__OSUnlockSram(TRUE);
while (!__OSSyncSram())
;
}
OSDisableInterrupts();
__OSCallResetFunctions(TRUE);
LCDisable();
if (reset == OS_RESET_HOTRESET) {
__OSDoHotReset(resetCode);
}
else if (reset == OS_RESET_RESTART) {
KillThreads();
OSEnableScheduler();
__OSReboot(resetCode, forceMenu);
}
KillThreads();
memset(OSPhysicalToCached(0x40), 0, 0xcc - 0x40);
memset(OSPhysicalToCached(0xd4), 0, 0xe8 - 0xd4);
memset(OSPhysicalToCached(0xf4), 0, 0xf8 - 0xf4);
memset(OSPhysicalToCached(0x3000), 0, 0xc0);
memset(OSPhysicalToCached(0x30c8), 0, 0xd4 - 0xc8);
memset(OSPhysicalToCached(0x30e2), 0, 1);
__PADDisableRecalibration(disableRecalibration);
}
u32 OSGetResetCode(void)
{
if (DAT_800030e2 != 0) {
return 0x80000000;
}
return ((DAT_cc003000.resetCode & ~7) >> 3);
}

View file

@ -0,0 +1,89 @@
#include <dolphin/os.h>
extern OSTime __OSGetSystemTime();
u8 GameChoice : (OS_BASE_CACHED | 0x30E3);
vu32 __PIRegs[12] : 0xCC003000;
extern OSTime __OSStartTime;
static OSResetCallback ResetCallback;
static BOOL Down;
static BOOL LastState;
static OSTime HoldUp;
static OSTime HoldDown;
void __OSResetSWInterruptHandler(__OSInterrupt interrupt, OSContext* context) {
OSResetCallback callback;
HoldDown = __OSGetSystemTime();
while (__OSGetSystemTime() - HoldDown < OSMicrosecondsToTicks(100) &&
!(__PIRegs[0] & 0x00010000)) {
;
}
if (!(__PIRegs[0] & 0x00010000)) {
LastState = Down = TRUE;
__OSMaskInterrupts(OS_INTERRUPTMASK_PI_RSW);
if (ResetCallback) {
callback = ResetCallback;
ResetCallback = NULL;
callback();
}
}
__PIRegs[0] = 2;
}
BOOL OSGetResetButtonState(void) {
BOOL enabled;
BOOL state;
u32 reg;
OSTime now;
enabled = OSDisableInterrupts();
now = __OSGetSystemTime();
reg = __PIRegs[0];
if (!(reg & 0x00010000)) {
if (!Down) {
Down = TRUE;
state = HoldUp ? TRUE : FALSE;
HoldDown = now;
} else {
state = (HoldUp || (OSMicrosecondsToTicks(100) < now - HoldDown)) ? TRUE : FALSE;
}
} else if (Down) {
Down = FALSE;
state = LastState;
if (state) {
HoldUp = now;
} else {
HoldUp = 0;
}
} else if (HoldUp && (now - HoldUp < OSMillisecondsToTicks(40))) {
state = TRUE;
} else {
state = FALSE;
HoldUp = 0;
}
LastState = state;
if (GameChoice & 0x3f) {
OSTime fire = (GameChoice & 0x3f) * 60;
fire = __OSStartTime + OSSecondsToTicks(fire);
if (fire < now) {
now -= fire;
now = OSTicksToSeconds(now) / 2;
if ((now & 1) == 0) {
state = TRUE;
} else {
state = FALSE;
}
}
}
OSRestoreInterrupts(enabled);
return state;
}

363
src/dolphin/os/OSRtc.c Normal file
View file

@ -0,0 +1,363 @@
#include <dolphin/OSRtcPriv.h>
#include <dolphin/exi.h>
#include <dolphin/os.h>
#define RTC_CMD_READ 0x20000000
#define RTC_CMD_WRITE 0xa0000000
#define RTC_SRAM_ADDR 0x00000100
#define RTC_SRAM_SIZE 64
#define RTC_CHAN 0
#define RTC_DEV 1
#define RTC_FREQ 3 // EXI_FREQ_8M
typedef struct SramControlBlock {
u8 sram[RTC_SRAM_SIZE];
u32 offset;
BOOL enabled;
BOOL locked;
BOOL sync;
void (*callback)(void);
} SramControlBlock;
static SramControlBlock Scb ATTRIBUTE_ALIGN(32);
static BOOL GetRTC(u32 *rtc)
{
BOOL err;
u32 cmd;
if (!EXILock(RTC_CHAN, RTC_DEV, 0)) {
return FALSE;
}
if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) {
EXIUnlock(RTC_CHAN);
return FALSE;
}
cmd = RTC_CMD_READ;
err = FALSE;
err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL);
err |= !EXISync(RTC_CHAN);
err |= !EXIImm(RTC_CHAN, &cmd, 4, 0, NULL);
err |= !EXISync(RTC_CHAN);
err |= !EXIDeselect(RTC_CHAN);
EXIUnlock(RTC_CHAN);
*rtc = cmd;
return !err;
}
BOOL __OSGetRTC(u32 *rtc)
{
BOOL err;
u32 t0;
u32 t1;
int i;
for (i = 0; i < 16; i++) {
err = FALSE;
err |= !GetRTC(&t0);
err |= !GetRTC(&t1);
if (err) {
break;
}
if (t0 == t1) {
*rtc = t0;
return TRUE;
}
}
return FALSE;
}
BOOL __OSSetRTC(u32 rtc)
{
BOOL err;
u32 cmd;
if (!EXILock(RTC_CHAN, RTC_DEV, 0)) {
return FALSE;
}
if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) {
EXIUnlock(RTC_CHAN);
return FALSE;
}
cmd = RTC_CMD_WRITE;
err = FALSE;
err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL);
err |= !EXISync(RTC_CHAN);
err |= !EXIImm(RTC_CHAN, &rtc, 4, 1, NULL);
err |= !EXISync(RTC_CHAN);
err |= !EXIDeselect(RTC_CHAN);
EXIUnlock(RTC_CHAN);
return !err;
}
static BOOL ReadSram(void *buffer)
{
BOOL err;
u32 cmd;
DCInvalidateRange(buffer, RTC_SRAM_SIZE);
if (!EXILock(RTC_CHAN, RTC_DEV, 0)) {
return FALSE;
}
if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) {
EXIUnlock(RTC_CHAN);
return FALSE;
}
cmd = RTC_CMD_READ | RTC_SRAM_ADDR;
err = FALSE;
err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL);
err |= !EXISync(RTC_CHAN);
err |= !EXIDma(RTC_CHAN, buffer, RTC_SRAM_SIZE, 0, NULL);
err |= !EXISync(RTC_CHAN);
err |= !EXIDeselect(RTC_CHAN);
EXIUnlock(RTC_CHAN);
return !err;
}
BOOL WriteSram(void *buffer, u32 offset, u32 size);
static void WriteSramCallback(s32 chan, OSContext *context)
{
Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset);
if (Scb.sync) {
Scb.offset = RTC_SRAM_SIZE;
}
}
BOOL WriteSram(void *buffer, u32 offset, u32 size)
{
BOOL err;
u32 cmd;
if (!EXILock(RTC_CHAN, RTC_DEV, WriteSramCallback)) {
return FALSE;
}
if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) {
EXIUnlock(RTC_CHAN);
return FALSE;
}
offset <<= 6;
cmd = RTC_CMD_WRITE | RTC_SRAM_ADDR + offset;
err = FALSE;
err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL);
err |= !EXISync(RTC_CHAN);
err |= !EXIImmEx(RTC_CHAN, buffer, (s32)size, 1);
err |= !EXIDeselect(RTC_CHAN);
EXIUnlock(RTC_CHAN);
return !err;
}
void __OSInitSram()
{
Scb.locked = Scb.enabled = FALSE;
Scb.sync = ReadSram(Scb.sram);
Scb.offset = RTC_SRAM_SIZE;
}
static void *LockSram(u32 offset)
{
BOOL enabled;
enabled = OSDisableInterrupts();
if (Scb.locked != FALSE) {
OSRestoreInterrupts(enabled);
return NULL;
}
Scb.enabled = enabled;
Scb.locked = TRUE;
return Scb.sram + offset;
}
OSSram *__OSLockSram()
{
return LockSram(0);
}
OSSramEx *__OSLockSramEx()
{
return LockSram(sizeof(OSSram));
}
static BOOL UnlockSram(BOOL commit, u32 offset)
{
u16 *p;
if (commit) {
if (offset == 0) {
OSSram *sram = (OSSram *)Scb.sram;
if (2u < (sram->flags & 3)) {
sram->flags &= ~3;
}
sram->checkSum = sram->checkSumInv = 0;
for (p = (u16 *)&sram->counterBias; p < (u16 *)(Scb.sram + sizeof(OSSram)); p++) {
sram->checkSum += *p;
sram->checkSumInv += ~*p;
}
}
if (offset < Scb.offset) {
Scb.offset = offset;
}
Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset);
if (Scb.sync) {
Scb.offset = RTC_SRAM_SIZE;
}
}
Scb.locked = FALSE;
OSRestoreInterrupts(Scb.enabled);
return Scb.sync;
}
BOOL __OSUnlockSram(BOOL commit)
{
return UnlockSram(commit, 0);
}
BOOL __OSUnlockSramEx(BOOL commit)
{
return UnlockSram(commit, sizeof(OSSram));
}
BOOL __OSSyncSram()
{
return Scb.sync;
}
BOOL __OSReadROM(void *buffer, s32 length, s32 offset)
{
BOOL err;
u32 cmd;
DCInvalidateRange(buffer, (u32)length);
if (!EXILock(RTC_CHAN, RTC_DEV, 0)) {
return FALSE;
}
if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) {
EXIUnlock(RTC_CHAN);
return FALSE;
}
cmd = (u32)(offset << 6);
err = FALSE;
err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL);
err |= !EXISync(RTC_CHAN);
err |= !EXIDma(RTC_CHAN, buffer, length, 0, NULL);
err |= !EXISync(RTC_CHAN);
err |= !EXIDeselect(RTC_CHAN);
EXIUnlock(RTC_CHAN);
return !err;
}
inline OSSram *__OSLockSramHACK()
{
return LockSram(0);
}
u32 OSGetSoundMode()
{
OSSram *sram;
u32 mode;
sram = __OSLockSramHACK();
mode = (sram->flags & 0x4) ? OS_SOUND_MODE_STEREO : OS_SOUND_MODE_MONO;
__OSUnlockSram(FALSE);
return mode;
}
void OSSetSoundMode(u32 mode)
{
OSSram *sram;
mode <<= 2;
mode &= 4;
sram = __OSLockSramHACK();
if (mode == (sram->flags & 4)) {
__OSUnlockSram(FALSE);
return;
}
sram->flags &= ~4;
sram->flags |= mode;
__OSUnlockSram(TRUE);
}
u32 OSGetProgressiveMode()
{
OSSram *sram;
u32 mode;
sram = __OSLockSramHACK();
mode = (sram->flags & 0x80) >> 7;
__OSUnlockSram(FALSE);
return mode;
}
void OSSetProgressiveMode(u32 mode)
{
OSSram *sram;
mode <<= 7;
mode &= 0x80;
sram = __OSLockSramHACK();
if (mode == (sram->flags & 0x80)) {
__OSUnlockSram(FALSE);
return;
}
sram->flags &= ~0x80;
sram->flags |= mode;
__OSUnlockSram(TRUE);
}
u8 OSGetLanguage()
{
OSSram *sram;
u8 language;
sram = __OSLockSramHACK();
language = sram->language;
__OSUnlockSram(FALSE);
return language;
}
u16 OSGetWirelessID(s32 channel)
{
OSSramEx *sram;
u16 id;
sram = __OSLockSramEx();
id = sram->wirelessPadID[channel];
__OSUnlockSramEx(FALSE);
return id;
}
void OSSetWirelessID(s32 channel, u16 id)
{
OSSramEx *sram;
sram = __OSLockSramEx();
if (sram->wirelessPadID[channel] != id) {
sram->wirelessPadID[channel] = id;
__OSUnlockSramEx(TRUE);
return;
}
__OSUnlockSramEx(FALSE);
}

View file

@ -0,0 +1,61 @@
#include <dolphin.h>
#include <dolphin/os.h>
void OSInitStopwatch(struct OSStopwatch *sw, char *name)
{
sw->name = name;
sw->total = 0;
sw->hits = 0;
sw->min = 0x00000000FFFFFFFF;
sw->max = 0;
}
void OSStartStopwatch(struct OSStopwatch *sw)
{
sw->running = 1;
sw->last = OSGetTime();
}
void OSStopStopwatch(struct OSStopwatch *sw)
{
long long interval;
if (sw->running != 0) {
interval = OSGetTime() - sw->last;
sw->total += interval;
sw->running = 0;
sw->hits++;
if (sw->max < interval) {
sw->max = interval;
}
if (interval < sw->min) {
sw->min = interval;
}
}
}
long long OSCheckStopwatch(struct OSStopwatch *sw)
{
long long currTotal;
currTotal = sw->total;
if (sw->running != 0) {
currTotal += OSGetTime() - sw->last;
}
return currTotal;
}
void OSResetStopwatch(struct OSStopwatch *sw)
{
OSInitStopwatch(sw, sw->name);
}
void OSDumpStopwatch(struct OSStopwatch *sw)
{
OSReport("Stopwatch [%s] :\n", sw->name);
OSReport("\tTotal= %lld us\n", OSTicksToMicroseconds(sw->total));
OSReport("\tHits = %d \n", sw->hits);
OSReport("\tMin = %lld us\n", OSTicksToMicroseconds(sw->min));
OSReport("\tMax = %lld us\n", OSTicksToMicroseconds(sw->max));
OSReport("\tMean = %lld us\n", OSTicksToMicroseconds(sw->total / sw->hits));
}

29
src/dolphin/os/OSSync.c Normal file
View file

@ -0,0 +1,29 @@
#include "string.h"
#include "dolphin/PPCArch.h"
#include "dolphin/os.h"
void __OSSystemCallVectorStart();
void __OSSystemCallVectorEnd();
static asm void SystemCallVector() {
nofralloc
entry __OSSystemCallVectorStart
mfspr r9, HID0
ori r10, r9, 8
mtspr HID0, r10
isync
sync
mtspr HID0, r9
rfi
entry __OSSystemCallVectorEnd
nop
}
void __OSInitSystemCall() {
void* addr = OSPhysicalToCached(0x00C00);
memcpy(addr, __OSSystemCallVectorStart, (size_t)__OSSystemCallVectorEnd - (size_t)__OSSystemCallVectorStart);
DCFlushRangeNoSync(addr, 0x100);
__sync();
ICInvalidateRange(addr, 0x100);
}

552
src/dolphin/os/OSThread.c Normal file
View file

@ -0,0 +1,552 @@
#include <dolphin/os/OSPriv.h>
static vu32 RunQueueBits;
static volatile BOOL RunQueueHint;
static vs32 Reschedule;
static OSThreadQueue RunQueue[32];
static OSThread IdleThread;
static OSThread DefaultThread;
static OSContext IdleContext;
static void DefaultSwitchThreadCallback(OSThread *from, OSThread *to);
static OSSwitchThreadCallback SwitchThreadCallback = DefaultSwitchThreadCallback;
OSThread *__OSCurrentThread : OS_BASE_CACHED + 0x00E4;
OSThreadQueue __OSActiveThreadQueue : OS_BASE_CACHED + 0x00DC;
volatile OSContext __OSCurrentContext : OS_BASE_CACHED + 0x00D4;
volatile OSContext *__OSFPUContext : OS_BASE_CACHED + 0x00D8;
static void DefaultSwitchThreadCallback(OSThread *from, OSThread *to) { }
extern u8 _stack_addr[];
extern u8 _stack_end[];
#define AddTail(queue, thread, link) \
do { \
OSThread *prev; \
\
prev = (queue)->tail; \
if (prev == NULL) \
(queue)->head = (thread); \
else \
prev->link.next = (thread); \
(thread)->link.prev = prev; \
(thread)->link.next = NULL; \
(queue)->tail = (thread); \
} while (0)
#define AddPrio(queue, thread, link) \
do { \
OSThread *prev, *next; \
\
for (next = (queue)->head; next && next->priority <= thread->priority; next = next->link.next) \
; \
if (next == NULL) \
AddTail(queue, thread, link); \
else { \
(thread)->link.next = next; \
prev = next->link.prev; \
next->link.prev = (thread); \
(thread)->link.prev = prev; \
if (prev == NULL) \
(queue)->head = (thread); \
else \
prev->link.next = (thread); \
} \
} while (0)
#define RemoveItem(queue, thread, link) \
do { \
OSThread *next, *prev; \
next = (thread)->link.next; \
prev = (thread)->link.prev; \
if (next == NULL) \
(queue)->tail = prev; \
else \
next->link.prev = prev; \
if (prev == NULL) \
(queue)->head = next; \
else \
prev->link.next = next; \
} while (0)
#define RemoveHead(queue, thread, link) \
do { \
OSThread *__next; \
(thread) = (queue)->head; \
__next = (thread)->link.next; \
if (__next == NULL) \
(queue)->tail = NULL; \
else \
__next->link.prev = NULL; \
(queue)->head = __next; \
} while (0)
static inline void OSInitMutexQueue(OSMutexQueue *queue)
{
queue->head = queue->tail = NULL;
}
static inline void OSSetCurrentThread(OSThread *thread)
{
__OSCurrentThread = thread;
}
void __OSThreadInit()
{
OSThread *thread = &DefaultThread;
int prio;
thread->state = OS_THREAD_STATE_RUNNING;
thread->attr = OS_THREAD_ATTR_DETACH;
thread->priority = thread->base = 16;
thread->suspend = 0;
thread->val = (void *)-1;
thread->mutex = NULL;
OSInitThreadQueue(&thread->queueJoin);
OSInitMutexQueue(&thread->queueMutex);
__OSFPUContext = &thread->context;
OSClearContext(&thread->context);
OSSetCurrentContext(&thread->context);
thread->stackBase = (void *)_stack_addr;
thread->stackEnd = (void *)_stack_end;
*(thread->stackEnd) = OS_THREAD_STACK_MAGIC;
OSSetCurrentThread(thread);
RunQueueBits = 0;
RunQueueHint = FALSE;
for (prio = OS_PRIORITY_MIN; prio <= OS_PRIORITY_MAX; ++prio) {
OSInitThreadQueue(&RunQueue[prio]);
}
OSInitThreadQueue(&__OSActiveThreadQueue);
AddTail(&__OSActiveThreadQueue, thread, linkActive);
OSClearContext(&IdleContext);
Reschedule = 0;
}
void OSInitThreadQueue(OSThreadQueue *queue)
{
queue->head = queue->tail = NULL;
}
OSThread *OSGetCurrentThread()
{
return __OSCurrentThread;
}
s32 OSDisableScheduler()
{
BOOL enabled;
s32 count;
enabled = OSDisableInterrupts();
count = Reschedule++;
OSRestoreInterrupts(enabled);
return count;
}
s32 OSEnableScheduler()
{
BOOL enabled;
s32 count;
enabled = OSDisableInterrupts();
count = Reschedule--;
OSRestoreInterrupts(enabled);
return count;
}
static void SetRun(OSThread *thread)
{
thread->queue = &RunQueue[thread->priority];
AddTail(thread->queue, thread, link);
RunQueueBits |= 1u << (OS_PRIORITY_MAX - thread->priority);
RunQueueHint = TRUE;
}
#pragma dont_inline on
static void UnsetRun(OSThread *thread)
{
OSThreadQueue *queue;
queue = thread->queue;
RemoveItem(queue, thread, link);
if (queue->head == 0)
RunQueueBits &= ~(1u << (OS_PRIORITY_MAX - thread->priority));
thread->queue = NULL;
}
#pragma dont_inline reset
OSPriority __OSGetEffectivePriority(OSThread *thread)
{
OSPriority priority;
OSMutex *mutex;
OSThread *blocked;
priority = thread->base;
for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) {
blocked = mutex->queue.head;
if (blocked && blocked->priority < priority) {
priority = blocked->priority;
}
}
return priority;
}
static OSThread *SetEffectivePriority(OSThread *thread, OSPriority priority)
{
switch (thread->state) {
case OS_THREAD_STATE_READY:
UnsetRun(thread);
thread->priority = priority;
SetRun(thread);
break;
case OS_THREAD_STATE_WAITING:
RemoveItem(thread->queue, thread, link);
thread->priority = priority;
AddPrio(thread->queue, thread, link);
if (thread->mutex) {
return thread->mutex->thread;
}
break;
case OS_THREAD_STATE_RUNNING:
RunQueueHint = TRUE;
thread->priority = priority;
break;
}
return NULL;
}
static void UpdatePriority(OSThread *thread)
{
OSPriority priority;
do {
if (0 < thread->suspend) {
break;
}
priority = __OSGetEffectivePriority(thread);
if (thread->priority == priority) {
break;
}
thread = SetEffectivePriority(thread, priority);
} while (thread);
}
static void __OSSwitchThread(OSThread *nextThread)
{
OSSetCurrentThread(nextThread);
OSSetCurrentContext(&nextThread->context);
OSLoadContext(&nextThread->context);
}
static OSThread *SelectThread(BOOL yield)
{
OSContext *currentContext;
OSThread *currentThread;
OSThread *nextThread;
OSPriority priority;
OSThreadQueue *queue;
if (0 < Reschedule) {
return 0;
}
currentContext = OSGetCurrentContext();
currentThread = OSGetCurrentThread();
if (currentContext != &currentThread->context) {
return 0;
}
if (currentThread) {
if (currentThread->state == OS_THREAD_STATE_RUNNING) {
if (!yield) {
priority = __cntlzw(RunQueueBits);
if (currentThread->priority <= priority) {
return 0;
}
}
currentThread->state = OS_THREAD_STATE_READY;
SetRun(currentThread);
}
if (!(currentThread->context.state & OS_CONTEXT_STATE_EXC) && OSSaveContext(&currentThread->context)) {
return 0;
}
}
OSSetCurrentThread(NULL);
if (RunQueueBits == 0) {
OSSetCurrentContext(&IdleContext);
do {
OSEnableInterrupts();
while (RunQueueBits == 0)
;
OSDisableInterrupts();
} while (RunQueueBits == 0);
OSClearContext(&IdleContext);
}
RunQueueHint = FALSE;
priority = __cntlzw(RunQueueBits);
queue = &RunQueue[priority];
RemoveHead(queue, nextThread, link);
if (queue->head == 0) {
RunQueueBits &= ~(1u << (OS_PRIORITY_MAX - priority));
}
nextThread->queue = NULL;
nextThread->state = OS_THREAD_STATE_RUNNING;
__OSSwitchThread(nextThread);
return nextThread;
}
void __OSReschedule()
{
if (!RunQueueHint) {
return;
}
SelectThread(FALSE);
}
void OSYieldThread(void)
{
BOOL enabled;
enabled = OSDisableInterrupts();
SelectThread(TRUE);
OSRestoreInterrupts(enabled);
}
int OSCreateThread(struct OSThread * thread, void * (* func)(void *), void * param, void * stack, unsigned long stackSize, long priority, unsigned short attr) {
int enabled;
unsigned long sp;
// why check this for an assert just to check it again right after?
if ((priority < 0) || (priority > 0x1F)) {
return 0;
}
thread->state = 1;
thread->attr = attr & 1U;
thread->base = priority;
thread->priority = priority;
thread->suspend = 1;
thread->val = (void*)-1;
thread->mutex = 0;
OSInitThreadQueue(&thread->queueJoin);
OSInitThreadQueue((void*)&thread->queueMutex); // why
sp = (u32)stack;
sp &= ~7;
sp -= 8;
((u32*)sp)[0] = 0;
((u32*)sp)[1] = 0;
OSInitContext(&thread->context, (u32)func, sp);
thread->context.lr = (unsigned long)&OSExitThread;
thread->context.gpr[3] = (unsigned long)param;
thread->stackBase = stack;
thread->stackEnd = (void*)((unsigned int)stack - stackSize);
*thread->stackEnd = 0xDEADBABE;
enabled = OSDisableInterrupts();
AddTail(&__OSActiveThreadQueue, thread, linkActive);
OSRestoreInterrupts(enabled);
return 1;
}
void OSExitThread(void *val)
{
int enabled = OSDisableInterrupts();
struct OSThread *currentThread = OSGetCurrentThread();
OSClearContext(&currentThread->context);
if (currentThread->attr & 1) {
RemoveItem(&__OSActiveThreadQueue, currentThread, linkActive);
currentThread->state = 0;
}
else {
currentThread->state = 8;
currentThread->val = val;
}
__OSUnlockAllMutex(currentThread);
OSWakeupThread(&currentThread->queueJoin);
RunQueueHint = 1;
if (RunQueueHint != 0) {
SelectThread(0);
}
OSRestoreInterrupts(enabled);
}
void OSCancelThread(OSThread *thread)
{
BOOL enabled;
enabled = OSDisableInterrupts();
switch (thread->state) {
case OS_THREAD_STATE_READY:
if (!(0 < thread->suspend)) {
UnsetRun(thread);
}
break;
case OS_THREAD_STATE_RUNNING:
RunQueueHint = TRUE;
break;
case OS_THREAD_STATE_WAITING:
RemoveItem(thread->queue, thread, link);
thread->queue = NULL;
if (!(0 < thread->suspend) && thread->mutex) {
UpdatePriority(thread->mutex->thread);
}
break;
default:
OSRestoreInterrupts(enabled);
return;
}
OSClearContext(&thread->context);
if (thread->attr & OS_THREAD_ATTR_DETACH) {
RemoveItem(&__OSActiveThreadQueue, thread, linkActive);
thread->state = 0;
}
else {
thread->state = OS_THREAD_STATE_MORIBUND;
}
__OSUnlockAllMutex(thread);
OSWakeupThread(&thread->queueJoin);
__OSReschedule();
OSRestoreInterrupts(enabled);
return;
}
s32 OSResumeThread(OSThread *thread)
{
BOOL enabled;
s32 suspendCount;
enabled = OSDisableInterrupts();
suspendCount = thread->suspend--;
if (thread->suspend < 0) {
thread->suspend = 0;
}
else if (thread->suspend == 0) {
switch (thread->state) {
case OS_THREAD_STATE_READY:
thread->priority = __OSGetEffectivePriority(thread);
SetRun(thread);
break;
case OS_THREAD_STATE_WAITING:
RemoveItem(thread->queue, thread, link);
thread->priority = __OSGetEffectivePriority(thread);
AddPrio(thread->queue, thread, link);
if (thread->mutex) {
UpdatePriority(thread->mutex->thread);
}
break;
}
__OSReschedule();
}
OSRestoreInterrupts(enabled);
return suspendCount;
}
s32 OSSuspendThread(OSThread *thread)
{
BOOL enabled;
s32 suspendCount;
enabled = OSDisableInterrupts();
suspendCount = thread->suspend++;
if (suspendCount == 0) {
switch (thread->state) {
case OS_THREAD_STATE_RUNNING:
RunQueueHint = TRUE;
thread->state = OS_THREAD_STATE_READY;
break;
case OS_THREAD_STATE_READY:
UnsetRun(thread);
break;
case OS_THREAD_STATE_WAITING:
RemoveItem(thread->queue, thread, link);
thread->priority = 32;
AddTail(thread->queue, thread, link);
if (thread->mutex) {
UpdatePriority(thread->mutex->thread);
}
break;
}
__OSReschedule();
}
OSRestoreInterrupts(enabled);
return suspendCount;
}
void OSSleepThread(OSThreadQueue *queue)
{
BOOL enabled;
OSThread *currentThread;
enabled = OSDisableInterrupts();
currentThread = OSGetCurrentThread();
currentThread->state = OS_THREAD_STATE_WAITING;
currentThread->queue = queue;
AddPrio(queue, currentThread, link);
RunQueueHint = TRUE;
__OSReschedule();
OSRestoreInterrupts(enabled);
}
void OSWakeupThread(OSThreadQueue *queue)
{
BOOL enabled;
OSThread *thread;
enabled = OSDisableInterrupts();
while (queue->head) {
RemoveHead(queue, thread, link);
thread->state = OS_THREAD_STATE_READY;
if (!(0 < thread->suspend)) {
SetRun(thread);
}
}
__OSReschedule();
OSRestoreInterrupts(enabled);
}
void OSClearStack(u8 val)
{
register u32 sp;
register u32 *p;
register u32 pattern;
pattern = ((u32)val << 24) | ((u32)val << 16) | ((u32)val << 8) | (u32)val;
sp = OSGetStackPointer();
for (p = __OSCurrentThread->stackEnd + 1; p < (u32 *)sp; ++p) {
*p = pattern;
}
}
struct OSThread *OSSetIdleFunction(void (*idleFunction)(void *), void *param, void *stack, unsigned long stackSize)
{
if (idleFunction) {
if (IdleThread.state == 0) {
OSCreateThread(&IdleThread, (void *)idleFunction, param, stack, stackSize, 0x1F, 1);
OSResumeThread(&IdleThread);
return &IdleThread;
}
}
else if (IdleThread.state != 0) {
OSCancelThread(&IdleThread);
}
return NULL;
}

146
src/dolphin/os/OSTime.c Normal file
View file

@ -0,0 +1,146 @@
#include <dolphin/os.h>
#define OS_TIME_MONTH_MAX 12
#define OS_TIME_WEEK_DAY_MAX 7
#define OS_TIME_YEAR_DAY_MAX 365
// End of each month in standard year
static s32 YearDays[OS_TIME_MONTH_MAX] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
// End of each month in leap year
static s32 LeapYearDays[OS_TIME_MONTH_MAX] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
asm OSTime OSGetTime(void)
{
// clang-format off
nofralloc
@0
mftbu r3
mftb r4
// Check for possible carry from TBL to TBU
mftbu r5
cmpw r3, r5
bne @0
blr
// clang-format on
}
asm OSTick OSGetTick(void) {
// clang-format off
nofralloc
mftb r3
blr
// clang-format on
}
#define OS_SYSTEMTIME_BASE 0x30D8
OSTime __OSGetSystemTime(void)
{
BOOL enabled;
OSTime *timeAdjustAddr = (OSTime *)(OS_BASE_CACHED + OS_SYSTEMTIME_BASE);
OSTime result;
enabled = OSDisableInterrupts();
result = *timeAdjustAddr + OSGetTime();
OSRestoreInterrupts(enabled);
return result;
}
OSTime __OSTimeToSystemTime(OSTime time)
{
BOOL enabled;
OSTime *timeAdjustAddr = (OSTime *)(OS_BASE_CACHED + OS_SYSTEMTIME_BASE);
OSTime result;
enabled = OSDisableInterrupts();
result = *timeAdjustAddr + time;
OSRestoreInterrupts(enabled);
return result;
}
static BOOL IsLeapYear(s32 year)
{
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
static s32 GetYearDays(s32 year, s32 mon)
{
return (IsLeapYear(year) ? LeapYearDays : YearDays)[mon];
}
static s32 GetLeapDays(s32 year)
{
if (year < 1) {
return 0;
}
return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400;
}
static void GetDates(s32 days, OSCalendarTime *cal)
{
s32 year;
s32 totalDays;
s32 *p_days;
s32 month;
cal->wday = (days + 6) % OS_TIME_WEEK_DAY_MAX;
for (year = days / OS_TIME_YEAR_DAY_MAX; days < (totalDays = year * OS_TIME_YEAR_DAY_MAX + GetLeapDays(year));) {
year--;
}
days -= totalDays;
cal->year = year;
cal->yday = days;
p_days = IsLeapYear(year) ? LeapYearDays : YearDays;
month = OS_TIME_MONTH_MAX;
while (days < p_days[--month]) {
;
}
cal->mon = month;
cal->mday = days - p_days[month] + 1;
}
#define BIAS (2000 * 365 + (2000 + 3) / 4 - (2000 - 1) / 100 + (2000 - 1) / 400)
#pragma push
#pragma dont_inline on
void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime *td)
{
int days;
int secs;
OSTime d;
d = ticks % OSSecondsToTicks(1);
if (d < 0) {
d += OSSecondsToTicks(1);
}
td->usec = (int)(OSTicksToMicroseconds(d) % 1000);
td->msec = (int)(OSTicksToMilliseconds(d) % 1000);
ticks -= d;
days = (int)(OSTicksToSeconds(ticks) / 86400 + BIAS);
secs = (int)(OSTicksToSeconds(ticks) % 86400);
if (secs < 0) {
days -= 1;
secs += 24 * 60 * 60;
}
GetDates(days, td);
td->hour = secs / 60 / 60;
td->min = (secs / 60) % 60;
td->sec = secs % 60;
}
#pragma dont_inline reset
OSTime OSCalendarTimeToTicks(OSCalendarTime *time)
{
;
;
}

View file

@ -0,0 +1,76 @@
#include <dolphin/PPCArch.h>
#include <dolphin/__ppc_eabi_init.h>
#ifdef __cplusplus
extern "C" {
#endif
void __OSPSInit();
void __OSCacheInit();
asm void __init_hardware(void)
{
// clang-format off
nofralloc
mfmsr r0
ori r0, r0, 0x2000
mtmsr r0
mflr r31
bl __OSPSInit
bl __OSCacheInit
mtlr r31
blr
// clang-format on
}
asm void __flush_cache(register void *address, register unsigned int size)
{
// clang-format off
nofralloc
lis r5, ~0
ori r5, r5, ~14
and r5, r5, r3
subf r3, r5, r3
add r4, r4, r3
loop:
dcbst r0, r5
sync
icbi r0, r5
addic r5, r5, 8
subic. r4, r4, 8
bge loop
isync
blr
// clang-format on
}
void __init_user()
{
__init_cpp();
}
typedef void (*voidfunctionptr)(void); // pointer to function returning void
__declspec(section ".init") extern voidfunctionptr _ctors[];
__declspec(section ".init") extern voidfunctionptr _dtors[];
void __init_cpp(void)
{
voidfunctionptr *constructor;
/*
* call static initializers
*/
for (constructor = _ctors; *constructor; constructor++) {
(*constructor)();
}
}
void _ExitProcess(void)
{
PPCHalt();
}
#ifdef __cplusplus
}
#endif

161
src/dolphin/os/__start.c Normal file
View file

@ -0,0 +1,161 @@
#include <dolphin/__start.h>
#include "__ppc_eabi_linker.h"
void __check_pad3(void) {
if ((Pad3Button & 0x0eef) == 0x0eef) {
OSResetSystem(OS_RESET_RESTART, 0, FALSE);
}
return;
}
__declspec(weak) asm void __start(void) {
// clang-format off
nofralloc
bl __init_registers
bl __init_hardware
li r0, -1
stwu r1, -8(r1)
stw r0, 4(r1)
stw r0, 0(r1)
bl __init_data
li r0, 0
lis r6, EXCEPTIONMASK_ADDR@ha
addi r6, r6, EXCEPTIONMASK_ADDR@l
stw r0, 0(r6)
lis r6, BOOTINFO2_ADDR@ha
addi r6, r6, BOOTINFO2_ADDR@l
lwz r6, 0(r6)
_check_TRK:
cmplwi r6, 0
beq _load_lomem_debug_flag
lwz r7, OS_BI2_DEBUGFLAG_OFFSET(r6)
b _check_debug_flag
_load_lomem_debug_flag:
lis r5, ARENAHI_ADDR@ha
addi r5, r5, ARENAHI_ADDR@l
lwz r5, 0(r5)
cmplwi r5, 0
beq _goto_main
lis r7, DEBUGFLAG_ADDR@ha
addi r7, r7, DEBUGFLAG_ADDR@l
lwz r7, 0(r7)
_check_debug_flag:
li r5, 0
cmplwi r7, 2
beq _goto_inittrk
cmplwi r7, 3
bne _goto_main
li r5, 1
_goto_inittrk:
lis r6, InitMetroTRK@ha
addi r6, r6, InitMetroTRK@l
mtlr r6
blrl
_goto_main:
lis r6, BOOTINFO2_ADDR@ha
addi r6, r6, BOOTINFO2_ADDR@l
lwz r5, 0(r6)
cmplwi r5, 0
beq+ _no_args
lwz r6, 8(r5)
cmplwi r6, 0
beq+ _no_args
add r6, r5, r6
lwz r14, 0(r6)
cmplwi r14, 0
beq _no_args
addi r15, r6, 4
mtctr r14
_loop:
addi r6, r6, 4
lwz r7, 0(r6)
add r7, r7, r5
stw r7, 0(r6)
bdnz _loop
lis r5, ARENAHI_ADDR@ha
addi r5, r5, ARENAHI_ADDR@l
rlwinm r7, r15, 0, 0, 0x1a
stw r7, 0(r5)
b _end_of_parseargs
_no_args:
li r14, 0
li r15, 0
_end_of_parseargs:
bl DBInit
bl OSInit
lis r4, DVD_DEVICECODE_ADDR@ha
addi r4, r4, DVD_DEVICECODE_ADDR@l
lhz r3, 0(r4)
andi. r5, r3, 0x8000
beq _check_pad3
andi. r3, r3, 0x7fff
cmplwi r3, 1
bne _goto_skip_init_bba
_check_pad3:
bl __check_pad3
_goto_skip_init_bba:
bl __init_user
mr r3, r14
mr r4, r15
bl main
b exit
// clang-format on
}
asm static void __init_registers(void) {
// clang-format off
nofralloc
lis r1, _stack_addr@h
ori r1, r1, _stack_addr@l
lis r2, _SDA2_BASE_@h
ori r2, r2, _SDA2_BASE_@l
lis r13, _SDA_BASE_@h
ori r13, r13, _SDA_BASE_@l
blr
// clang-format on
}
inline static void __copy_rom_section(void* dst, const void* src, unsigned long size) {
if (size && (dst != src)) {
memcpy(dst, src, size);
__flush_cache(dst, size);
}
}
inline static void __init_bss_section(void* dst, unsigned long size) {
if (size) {
memset(dst, 0, size);
}
}
#pragma scheduling off
void __init_data(void) {
__rom_copy_info* dci;
__bss_init_info* bii;
dci = _rom_copy_info;
while (TRUE) {
if (dci->size == 0)
break;
__copy_rom_section(dci->addr, dci->rom, dci->size);
dci++;
}
bii = _bss_init_info;
while (TRUE) {
if (bii->size == 0)
break;
__init_bss_section(bii->addr, bii->size);
bii++;
}
}