Imported most of dolphin/os
This commit is contained in:
parent
023cd90675
commit
970da00ce2
35 changed files with 6591 additions and 131 deletions
645
src/dolphin/os/OS.c
Normal file
645
src/dolphin/os/OS.c
Normal 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
199
src/dolphin/os/OSAlarm.c
Normal 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
531
src/dolphin/os/OSAlloc.c
Normal 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
53
src/dolphin/os/OSArena.c
Normal 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;
|
||||
}
|
||||
118
src/dolphin/os/OSAudioSystem.c
Normal file
118
src/dolphin/os/OSAudioSystem.c
Normal 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
450
src/dolphin/os/OSCache.c
Normal 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
555
src/dolphin/os/OSContext.c
Normal 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
115
src/dolphin/os/OSError.c
Normal 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
323
src/dolphin/os/OSFont.c
Normal 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;
|
||||
}
|
||||
434
src/dolphin/os/OSInterrupt.c
Normal file
434
src/dolphin/os/OSInterrupt.c
Normal 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
504
src/dolphin/os/OSLink.c
Normal 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
230
src/dolphin/os/OSMemory.c
Normal 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);
|
||||
}
|
||||
91
src/dolphin/os/OSMessage.c
Normal file
91
src/dolphin/os/OSMessage.c
Normal 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
244
src/dolphin/os/OSMutex.c
Normal 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(¤tThread->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(¤tThread->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(¤tThread->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(¤tThread->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
94
src/dolphin/os/OSReboot.c
Normal 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
203
src/dolphin/os/OSReset.c
Normal 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);
|
||||
}
|
||||
89
src/dolphin/os/OSResetSW.c
Normal file
89
src/dolphin/os/OSResetSW.c
Normal 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
363
src/dolphin/os/OSRtc.c
Normal 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);
|
||||
}
|
||||
61
src/dolphin/os/OSStopwatch.c
Normal file
61
src/dolphin/os/OSStopwatch.c
Normal 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
29
src/dolphin/os/OSSync.c
Normal 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
552
src/dolphin/os/OSThread.c
Normal 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 != ¤tThread->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(¤tThread->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(¤tThread->context);
|
||||
if (currentThread->attr & 1) {
|
||||
RemoveItem(&__OSActiveThreadQueue, currentThread, linkActive);
|
||||
currentThread->state = 0;
|
||||
}
|
||||
else {
|
||||
currentThread->state = 8;
|
||||
currentThread->val = val;
|
||||
}
|
||||
__OSUnlockAllMutex(currentThread);
|
||||
OSWakeupThread(¤tThread->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
146
src/dolphin/os/OSTime.c
Normal 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)
|
||||
{
|
||||
;
|
||||
;
|
||||
}
|
||||
76
src/dolphin/os/__ppc_eabi_init.c
Normal file
76
src/dolphin/os/__ppc_eabi_init.c
Normal 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
161
src/dolphin/os/__start.c
Normal 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++;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue