mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-05-23 06:34:18 -04:00
Link all of dolphin/os
This commit is contained in:
@@ -20,6 +20,40 @@ block_relocations:
|
||||
- source: 0x80052D58
|
||||
|
||||
add_relocations:
|
||||
# OS.c
|
||||
- source: .text:0x80078984
|
||||
type: ha
|
||||
target: __ArenaLo
|
||||
- source: .text:0x80078988
|
||||
type: l
|
||||
target: __ArenaLo
|
||||
- source: .text:0x800789BC
|
||||
type: ha
|
||||
target: _stack_addr
|
||||
- source: .text:0x800789C0
|
||||
type: l
|
||||
target: _stack_addr
|
||||
- source: .text:0x800789E0
|
||||
type: ha
|
||||
target: __ArenaHi
|
||||
- source: .text:0x800789E4
|
||||
type: l
|
||||
target: __ArenaHi
|
||||
|
||||
# OSThread.c
|
||||
- source: .text:0x8007DC18
|
||||
type: ha
|
||||
target: _stack_addr
|
||||
- source: .text:0x8007DC1C
|
||||
type: l
|
||||
target: _stack_addr
|
||||
- source: .text:0x8007DC20
|
||||
type: ha
|
||||
target: _stack_end
|
||||
- source: .text:0x8007DC28
|
||||
type: l
|
||||
target: _stack_end
|
||||
|
||||
# emu64
|
||||
- source: .text:0x8004F4F4 # setup_texture_tile (inlined texture_cache_select)
|
||||
type: ha
|
||||
|
||||
@@ -12,10 +12,10 @@ SECTIONS
|
||||
} > text
|
||||
|
||||
_stack_end = ($LAST_SECTION_SYMBOL + SIZEOF($LAST_SECTION_NAME)+ 0x7) & ~0x7;
|
||||
_stack_addr = (_stack_end + 0x2000 + 0x7) & ~0x7;
|
||||
_db_stack_addr = (_stack_addr + 0x1000);
|
||||
_stack_addr = (_stack_end + 0x1000 + 0x7) & ~0x7;
|
||||
_db_stack_addr = (_stack_addr + 0x2000);
|
||||
_db_stack_end = _stack_addr;
|
||||
__ArenaLo = _db_stack_addr;
|
||||
__ArenaLo = (_db_stack_addr + 0x1F) & ~0x1F;
|
||||
__ArenaHi = 0x81700000;
|
||||
}
|
||||
|
||||
|
||||
+14
-14
@@ -565,27 +565,27 @@ config.libs = [
|
||||
[
|
||||
Object(Matching, "dolphin/os/__ppc_eabi_init.cpp"),
|
||||
Object(Matching, "dolphin/os/__start.c"),
|
||||
Object(NonMatching, "dolphin/os/OS.c"),
|
||||
Object(Matching, "dolphin/os/OS.c"),
|
||||
Object(Matching, "dolphin/os/OSAlarm.c"),
|
||||
Object(NonMatching, "dolphin/os/OSAlloc.c"),
|
||||
Object(Matching, "dolphin/os/OSAlloc.c"),
|
||||
Object(Matching, "dolphin/os/OSArena.c"),
|
||||
Object(Matching, "dolphin/os/OSAudioSystem.c"),
|
||||
Object(Matching, "dolphin/os/OSCache.c"),
|
||||
Object(Matching, "dolphin/os/OSContext.c"),
|
||||
Object(Matching, "dolphin/os/OSError.c"),
|
||||
Object(NonMatching, "dolphin/os/OSFont.c"),
|
||||
Object(NonMatching, "dolphin/os/OSInterrupt.c"),
|
||||
Object(NonMatching, "dolphin/os/OSLink.c"),
|
||||
Object(NonMatching, "dolphin/os/OSMemory.c"),
|
||||
Object(NonMatching, "dolphin/os/OSMessage.c"),
|
||||
Object(NonMatching, "dolphin/os/OSMutex.c"),
|
||||
Object(NonMatching, "dolphin/os/OSReboot.c"),
|
||||
Object(NonMatching, "dolphin/os/OSReset.c"),
|
||||
Object(NonMatching, "dolphin/os/OSResetSW.c"),
|
||||
Object(Matching, "dolphin/os/OSFont.c"),
|
||||
Object(Matching, "dolphin/os/OSInterrupt.c"),
|
||||
Object(Matching, "dolphin/os/OSLink.c"),
|
||||
Object(Matching, "dolphin/os/OSMemory.c"),
|
||||
Object(Matching, "dolphin/os/OSMessage.c"),
|
||||
Object(Matching, "dolphin/os/OSMutex.c"),
|
||||
Object(Matching, "dolphin/os/OSReboot.c"),
|
||||
Object(Matching, "dolphin/os/OSReset.c"),
|
||||
Object(Matching, "dolphin/os/OSResetSW.c"),
|
||||
Object(Matching, "dolphin/os/OSRtc.c"),
|
||||
Object(NonMatching, "dolphin/os/OSSync.c"),
|
||||
Object(NonMatching, "dolphin/os/OSThread.c"),
|
||||
Object(NonMatching, "dolphin/os/OSTime.c"),
|
||||
Object(Matching, "dolphin/os/OSSync.c"),
|
||||
Object(Matching, "dolphin/os/OSThread.c"),
|
||||
Object(Matching, "dolphin/os/OSTime.c"),
|
||||
],
|
||||
),
|
||||
DolphinLib(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "types.h"
|
||||
#include "dolphin/os/OSModule.h"
|
||||
#include "dolphin/os/OSLink.h"
|
||||
#include "dolphin/os/OSTime.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -94,6 +94,23 @@ void PPCSetFpNonIEEEMode(void);
|
||||
#define MSR_RI 0x00000002 // Recoverable interrupt
|
||||
#define MSR_LE 0x00000001 // Little Endian
|
||||
|
||||
#define MSR_POW_BIT 13 // Power Management
|
||||
#define MSR_ILE_BIT 15 // Interrupt Little Endian
|
||||
#define MSR_EE_BIT 16 // external interrupt
|
||||
#define MSR_PR_BIT 17 // privilege level (should be 0)
|
||||
#define MSR_FP_BIT 18 // floating point available
|
||||
#define MSR_ME_BIT 19 // machine check enable
|
||||
#define MSR_FE0_BIT 20 // floating point exception enable
|
||||
#define MSR_SE_BIT 21 // single step trace enable
|
||||
#define MSR_BE_BIT 22 // branch trace enable
|
||||
#define MSR_FE1_BIT 23 // floating point exception enable
|
||||
#define MSR_IP_BIT 25 // Exception prefix
|
||||
#define MSR_IR_BIT 26 // instruction relocate
|
||||
#define MSR_DR_BIT 27 // data relocate
|
||||
#define MSR_PM_BIT 29 // Performance monitor marked mode
|
||||
#define MSR_RI_BIT 30 // Recoverable interrupt
|
||||
#define MSR_LE_BIT 31 // Little Endian
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-14
@@ -2,6 +2,7 @@
|
||||
#define DB_H
|
||||
|
||||
#include "types.h"
|
||||
#include <dolphin/db/DBInterface.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
@@ -9,20 +10,8 @@ extern "C"{
|
||||
|
||||
#define OS_DBINTERFACE_ADDR 0x00000040
|
||||
|
||||
typedef struct DBInterface
|
||||
{
|
||||
u32 bPresent;
|
||||
u32 exceptionMask;
|
||||
void (*ExceptionDestination) ( void );
|
||||
void *exceptionReturn;
|
||||
} DBInterface;
|
||||
|
||||
extern DBInterface* __DBInterface;
|
||||
|
||||
void DBInit(void);
|
||||
void DBInitComm(int* inputFlagPtr, int* mtrCallback);
|
||||
static void __DBExceptionDestination(void);
|
||||
void DBPrintf(char* format, ...);
|
||||
BOOL DBIsDebuggerPresent(void);
|
||||
void DBPrintf(char* str, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef _DOLPHIN_DBINTERFACE_H_
|
||||
#define _DOLPHIN_DBINTERFACE_H_
|
||||
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct DBInterface {
|
||||
u32 bPresent;
|
||||
u32 exceptionMask;
|
||||
void (*ExceptionDestination)(void);
|
||||
void* exceptionReturn;
|
||||
} DBInterface;
|
||||
|
||||
extern DBInterface* __DBInterface;
|
||||
|
||||
void DBInit(void);
|
||||
void DBInitComm(int* inputFlagPtr, int* mtrCallback);
|
||||
void __DBExceptionDestination(void);
|
||||
void __DBExceptionDestinationAux(void);
|
||||
BOOL __DBIsExceptionMarked(__OSException exception);
|
||||
void __DBMarkException(u8 exception, int value);
|
||||
void __DBSetPresent(u32 value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "dolphin/os/OSError.h"
|
||||
#include "dolphin/os/OSInterrupt.h"
|
||||
#include "dolphin/os/OSModule.h"
|
||||
#include "dolphin/os/OSLink.h"
|
||||
#include "dolphin/os/OSMemory.h"
|
||||
#include "dolphin/os/OSMessage.h"
|
||||
#include "libforest/osreport.h" /* OSReport funcs */
|
||||
@@ -100,6 +101,18 @@ typedef struct OSBootInfo_s {
|
||||
#define OS_BASE_CACHED (OS_CACHED_REGION_PREFIX << 16)
|
||||
#define OS_BASE_UNCACHED (OS_UNCACHED_REGION_PREFIX << 16)
|
||||
|
||||
typedef struct BI2Debug {
|
||||
/* 0x00 */ s32 debugMonSize;
|
||||
/* 0x04 */ s32 simMemSize;
|
||||
/* 0x08 */ u32 argOffset;
|
||||
/* 0x0C */ u32 debugFlag;
|
||||
/* 0x10 */ int trackLocation;
|
||||
/* 0x14 */ int trackSize;
|
||||
/* 0x18 */ u32 countryCode;
|
||||
/* 0x1C */ u8 unk[8];
|
||||
/* 0x24 */ u32 padSpec;
|
||||
} BI2Debug;
|
||||
|
||||
#ifdef __MWERKS__
|
||||
u32 __OSPhysicalMemSize : (OS_BASE_CACHED | 0x0028);
|
||||
volatile int __OSTVMode : (OS_BASE_CACHED | 0x00CC);
|
||||
|
||||
@@ -9,6 +9,7 @@ extern "C" {
|
||||
|
||||
typedef u16 OSError;
|
||||
typedef void (*OSErrorHandler)(OSError error, OSContext *context, ...);
|
||||
typedef void (*OSErrorHandlerEx)(OSError error, OSContext* context, ...);
|
||||
|
||||
#define OS_ERROR_SYSTEM_RESET 0
|
||||
#define OS_ERROR_MACHINE_CHECK 1
|
||||
@@ -37,4 +38,4 @@ extern u32 __OSFpscrEnableBits;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -30,6 +30,26 @@ typedef void (*__OSExceptionHandler)(__OSException exception, OSContext* context
|
||||
__OSExceptionHandler __OSSetExceptionHandler(__OSException exception, __OSExceptionHandler handler);
|
||||
__OSExceptionHandler __OSGetExceptionHandler(__OSException exception);
|
||||
|
||||
#define OS_EXCEPTION_SAVE_GPRS(context) \
|
||||
stw r0, OS_CONTEXT_R0(context); \
|
||||
stw r1, OS_CONTEXT_R1(context); \
|
||||
stw r2, OS_CONTEXT_R2(context); \
|
||||
stmw r6, OS_CONTEXT_R6(context); \
|
||||
mfspr r0, GQR1; \
|
||||
stw r0, OS_CONTEXT_GQR1(context); \
|
||||
mfspr r0, GQR2; \
|
||||
stw r0, OS_CONTEXT_GQR2(context); \
|
||||
mfspr r0, GQR3; \
|
||||
stw r0, OS_CONTEXT_GQR3(context); \
|
||||
mfspr r0, GQR4; \
|
||||
stw r0, OS_CONTEXT_GQR4(context); \
|
||||
mfspr r0, GQR5; \
|
||||
stw r0, OS_CONTEXT_GQR5(context); \
|
||||
mfspr r0, GQR6; \
|
||||
stw r0, OS_CONTEXT_GQR6(context); \
|
||||
mfspr r0, GQR7; \
|
||||
stw r0, OS_CONTEXT_GQR7(context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OS_FONT_ROM_SIZE_ANSI 0x03000
|
||||
#define OS_FONT_ROM_SIZE_SJIS 0x4D000
|
||||
|
||||
typedef struct OSFontHeader {
|
||||
u16 fontType; // _00
|
||||
u16 firstChar; // _02, first char code defined in font.
|
||||
|
||||
@@ -49,60 +49,98 @@ typedef enum OSInterruptType {
|
||||
OS_INTR_MAX
|
||||
} OSInterruptType;
|
||||
|
||||
#define OS_INTRMASK_MEM_0 (0x80000000U >> OS_INTR_MEM_0)
|
||||
#define OS_INTRMASK_MEM_1 (0x80000000U >> OS_INTR_MEM_1)
|
||||
#define OS_INTRMASK_MEM_2 (0x80000000U >> OS_INTR_MEM_2)
|
||||
#define OS_INTRMASK_MEM_3 (0x80000000U >> OS_INTR_MEM_3)
|
||||
#define OS_INTRMASK_MEM_ADDRESS (0x80000000U >> OS_INTR_MEM_ADDRESS)
|
||||
#define OS_INTRMASK_DSP_AI (0x80000000U >> OS_INTR_DSP_AI)
|
||||
#define OS_INTRMASK_DSP_ARAM (0x80000000U >> OS_INTR_DSP_ARAM)
|
||||
#define OS_INTRMASK_DSP_DSP (0x80000000U >> OS_INTR_DSP_DSP)
|
||||
#define OS_INTRMASK_AI_AI (0x80000000U >> OS_INTR_AI_AI)
|
||||
#define OS_INTRMASK_EXI_0_EXI (0x80000000U >> OS_INTR_EXI_0_EXI)
|
||||
#define OS_INTRMASK_EXI_0_TC (0x80000000U >> OS_INTR_EXI_0_TC)
|
||||
#define OS_INTRMASK_EXI_0_EXT (0x80000000U >> OS_INTR_EXI_0_EXT)
|
||||
#define OS_INTRMASK_EXI_1_EXI (0x80000000U >> OS_INTR_EXI_1_EXI)
|
||||
#define OS_INTRMASK_EXI_1_TC (0x80000000U >> OS_INTR_EXI_1_TC)
|
||||
#define OS_INTRMASK_EXI_1_EXT (0x80000000U >> OS_INTR_EXI_1_EXT)
|
||||
#define OS_INTRMASK_EXI_2_EXI (0x80000000U >> OS_INTR_EXI_2_EXI)
|
||||
#define OS_INTRMASK_EXI_2_TC (0x80000000U >> OS_INTR_EXI_2_TC)
|
||||
#define OS_INTRMASK_PI_CP (0x80000000U >> OS_INTR_PI_CP)
|
||||
#define OS_INTRMASK_PI_PE_TOKEN (0x80000000U >> OS_INTR_PI_PE_TOKEN)
|
||||
#define OS_INTRMASK_PI_PE_FINISH (0x80000000U >> OS_INTR_PI_PE_FINISH)
|
||||
#define OS_INTRMASK_PI_SI (0x80000000U >> OS_INTR_PI_SI)
|
||||
#define OS_INTRMASK_PI_DI (0x80000000U >> OS_INTR_PI_DI)
|
||||
#define OS_INTRMASK_PI_RSW (0x80000000U >> OS_INTR_PI_RSW)
|
||||
#define OS_INTRMASK_PI_ERROR (0x80000000U >> OS_INTR_PI_ERROR)
|
||||
#define OS_INTRMASK_PI_VI (0x80000000U >> OS_INTR_PI_VI)
|
||||
#define OS_INTRMASK_PI_DEBUG (0x80000000U >> OS_INTR_PI_DEBUG)
|
||||
#define OS_INTRMASK_PI_HSP (0x80000000U >> OS_INTR_PI_HSP)
|
||||
#define __OS_INTERRUPT_MEM_0 0
|
||||
#define __OS_INTERRUPT_MEM_1 1
|
||||
#define __OS_INTERRUPT_MEM_2 2
|
||||
#define __OS_INTERRUPT_MEM_3 3
|
||||
#define __OS_INTERRUPT_MEM_ADDRESS 4
|
||||
#define __OS_INTERRUPT_DSP_AI 5
|
||||
#define __OS_INTERRUPT_DSP_ARAM 6
|
||||
#define __OS_INTERRUPT_DSP_DSP 7
|
||||
#define __OS_INTERRUPT_AI_AI 8
|
||||
#define __OS_INTERRUPT_EXI_0_EXI 9
|
||||
#define __OS_INTERRUPT_EXI_0_TC 10
|
||||
#define __OS_INTERRUPT_EXI_0_EXT 11
|
||||
#define __OS_INTERRUPT_EXI_1_EXI 12
|
||||
#define __OS_INTERRUPT_EXI_1_TC 13
|
||||
#define __OS_INTERRUPT_EXI_1_EXT 14
|
||||
#define __OS_INTERRUPT_EXI_2_EXI 15
|
||||
#define __OS_INTERRUPT_EXI_2_TC 16
|
||||
#define __OS_INTERRUPT_PI_CP 17
|
||||
#define __OS_INTERRUPT_PI_PE_TOKEN 18
|
||||
#define __OS_INTERRUPT_PI_PE_FINISH 19
|
||||
#define __OS_INTERRUPT_PI_SI 20
|
||||
#define __OS_INTERRUPT_PI_DI 21
|
||||
#define __OS_INTERRUPT_PI_RSW 22
|
||||
#define __OS_INTERRUPT_PI_ERROR 23
|
||||
#define __OS_INTERRUPT_PI_VI 24
|
||||
#define __OS_INTERRUPT_PI_DEBUG 25
|
||||
#define __OS_INTERRUPT_PI_HSP 26
|
||||
#define __OS_INTERRUPT_MAX 32
|
||||
|
||||
#define OS_INTRMASK_MEM \
|
||||
(OS_INTRMASK_MEM_0 | OS_INTRMASK_MEM_1 | OS_INTRMASK_MEM_2 | \
|
||||
OS_INTRMASK_MEM_3 | OS_INTRMASK_MEM_ADDRESS)
|
||||
#define OS_INTERRUPTMASK(interrupt) (0x80000000u >> (interrupt))
|
||||
|
||||
#define OS_INTRMASK_AI (OS_INTRMASK_AI_AI)
|
||||
|
||||
#define OS_INTRMASK_DSP \
|
||||
(OS_INTRMASK_DSP_AI | OS_INTRMASK_DSP_ARAM | OS_INTRMASK_DSP_DSP)
|
||||
|
||||
#define OS_INTRMASK_EXI_0 \
|
||||
(OS_INTRMASK_EXI_0_EXI | OS_INTRMASK_EXI_0_TC | OS_INTRMASK_EXI_0_EXT)
|
||||
#define OS_INTRMASK_EXI_1 \
|
||||
(OS_INTRMASK_EXI_1_EXI | OS_INTRMASK_EXI_1_TC | OS_INTRMASK_EXI_1_EXT)
|
||||
#define OS_INTRMASK_EXI_2 (OS_INTRMASK_EXI_2_EXI | OS_INTRMASK_EXI_2_TC)
|
||||
#define OS_INTRMASK_EXI \
|
||||
(OS_INTRMASK_EXI_0_EXI | OS_INTRMASK_EXI_0_TC | OS_INTRMASK_EXI_0_EXT | \
|
||||
OS_INTRMASK_EXI_1_EXI | OS_INTRMASK_EXI_1_TC | OS_INTRMASK_EXI_1_EXT | \
|
||||
OS_INTRMASK_EXI_2_EXI | OS_INTRMASK_EXI_2_TC)
|
||||
|
||||
#define OS_INTRMASK_PI \
|
||||
(OS_INTRMASK_PI_CP | OS_INTRMASK_PI_SI | OS_INTRMASK_PI_DI | \
|
||||
OS_INTRMASK_PI_RSW | OS_INTRMASK_PI_ERROR | OS_INTRMASK_PI_VI | \
|
||||
OS_INTRMASK_PI_PE_TOKEN | OS_INTRMASK_PI_PE_FINISH | \
|
||||
OS_INTRMASK_PI_DEBUG | OS_INTRMASK_PI_HSP)
|
||||
|
||||
#define OS_INTRMASK_PI_PE (OS_INTRMASK_PI_PE_TOKEN | OS_INTRMASK_PI_PE_FINISH)
|
||||
#define OS_INTERRUPTMASK_MEM_0 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0)
|
||||
#define OS_INTERRUPTMASK_MEM_1 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_1)
|
||||
#define OS_INTERRUPTMASK_MEM_2 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_2)
|
||||
#define OS_INTERRUPTMASK_MEM_3 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_3)
|
||||
#define OS_INTERRUPTMASK_MEM_ADDRESS \
|
||||
OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_ADDRESS)
|
||||
#define OS_INTERRUPTMASK_MEM_RESET \
|
||||
(OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 \
|
||||
| OS_INTERRUPTMASK_MEM_3)
|
||||
#define OS_INTERRUPTMASK_MEM \
|
||||
(OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 \
|
||||
| OS_INTERRUPTMASK_MEM_3 | OS_INTERRUPTMASK_MEM_ADDRESS)
|
||||
#define OS_INTERRUPTMASK_DSP_AI OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_AI)
|
||||
#define OS_INTERRUPTMASK_DSP_ARAM OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_ARAM)
|
||||
#define OS_INTERRUPTMASK_DSP_DSP OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_DSP)
|
||||
#define OS_INTERRUPTMASK_DSP \
|
||||
(OS_INTERRUPTMASK_DSP_AI | OS_INTERRUPTMASK_DSP_ARAM \
|
||||
| OS_INTERRUPTMASK_DSP_DSP)
|
||||
#define OS_INTERRUPTMASK_AI_AI OS_INTERRUPTMASK(__OS_INTERRUPT_AI_AI)
|
||||
#define OS_INTERRUPTMASK_AI (OS_INTERRUPTMASK_AI_AI)
|
||||
#define OS_INTERRUPTMASK_EXI_0_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_0_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_0_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_0 \
|
||||
(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC \
|
||||
| OS_INTERRUPTMASK_EXI_0_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_1_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_1_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_1_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_1 \
|
||||
(OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC \
|
||||
| OS_INTERRUPTMASK_EXI_1_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_2_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_2_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_2_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_2_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_2 \
|
||||
(OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC)
|
||||
#define OS_INTERRUPTMASK_EXI \
|
||||
(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC \
|
||||
| OS_INTERRUPTMASK_EXI_0_EXT | OS_INTERRUPTMASK_EXI_1_EXI \
|
||||
| OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT \
|
||||
| OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC)
|
||||
#define OS_INTERRUPTMASK_PI_PE_TOKEN \
|
||||
OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_TOKEN)
|
||||
#define OS_INTERRUPTMASK_PI_PE_FINISH \
|
||||
OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_FINISH)
|
||||
#define OS_INTERRUPTMASK_PI_PE \
|
||||
(OS_INTERRUPTMASK_PI_PE_TOKEN | OS_INTERRUPTMASK_PI_PE_FINISH)
|
||||
#define OS_INTERRUPTMASK_PI_CP OS_INTERRUPTMASK(__OS_INTERRUPT_PI_CP)
|
||||
#define OS_INTERRUPTMASK_PI_SI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_SI)
|
||||
#define OS_INTERRUPTMASK_PI_DI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DI)
|
||||
#define OS_INTERRUPTMASK_PI_RSW OS_INTERRUPTMASK(__OS_INTERRUPT_PI_RSW)
|
||||
#define OS_INTERRUPTMASK_PI_ERROR OS_INTERRUPTMASK(__OS_INTERRUPT_PI_ERROR)
|
||||
#define OS_INTERRUPTMASK_PI_VI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_VI)
|
||||
#define OS_INTERRUPTMASK_PI_DEBUG OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DEBUG)
|
||||
#define OS_INTERRUPTMASK_PI_HSP OS_INTERRUPTMASK(__OS_INTERRUPT_PI_HSP)
|
||||
#define OS_INTERRUPTMASK_PI \
|
||||
(OS_INTERRUPTMASK_PI_CP | OS_INTERRUPTMASK_PI_SI | OS_INTERRUPTMASK_PI_DI \
|
||||
| OS_INTERRUPTMASK_PI_RSW | OS_INTERRUPTMASK_PI_ERROR \
|
||||
| OS_INTERRUPTMASK_PI_VI | OS_INTERRUPTMASK_PI_PE_TOKEN \
|
||||
| OS_INTERRUPTMASK_PI_PE_FINISH | OS_INTERRUPTMASK_PI_DEBUG \
|
||||
| OS_INTERRUPTMASK_PI_HSP)
|
||||
|
||||
typedef void (*__OSInterruptHandler)(__OSInterrupt, OSContext*);
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#ifndef OSLINK_H
|
||||
#define OSLINK_H
|
||||
|
||||
#include <dolphin/os/OSUtil.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OS_MODULE_VERSION 2
|
||||
|
||||
typedef struct OSModuleHeader OSModuleHeader;
|
||||
|
||||
typedef u32 OSModuleID;
|
||||
typedef struct OSModuleQueue OSModuleQueue;
|
||||
typedef struct OSModuleLink OSModuleLink;
|
||||
typedef struct OSModuleInfo OSModuleInfo;
|
||||
typedef struct OSSectionInfo OSSectionInfo;
|
||||
typedef struct OSImportInfo OSImportInfo;
|
||||
typedef struct OSRel OSRel;
|
||||
|
||||
struct OSModuleQueue {
|
||||
OSModuleInfo* head;
|
||||
OSModuleInfo* tail;
|
||||
};
|
||||
|
||||
OSModuleQueue __OSModuleList AT_ADDRESS(0x800030C8);
|
||||
void* __OSStringTable AT_ADDRESS(0x800030D0);
|
||||
|
||||
struct OSModuleLink {
|
||||
OSModuleInfo* next;
|
||||
OSModuleInfo* prev;
|
||||
};
|
||||
|
||||
struct OSSectionInfo {
|
||||
u32 offset;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct OSModuleInfo {
|
||||
OSModuleID id; // unique identifier for the module
|
||||
OSModuleLink link; // doubly linked list of modules
|
||||
u32 numSections; // # of sections
|
||||
u32 sectionInfoOffset; // offset to section info table
|
||||
u32 nameOffset; // offset to module name
|
||||
u32 nameSize; // size of module name
|
||||
u32 version; // version number
|
||||
};
|
||||
|
||||
struct OSModuleHeader {
|
||||
// CAUTION: info must be the 1st member
|
||||
OSModuleInfo info;
|
||||
|
||||
// OS_MODULE_VERSION == 1
|
||||
u32 bssSize; // total size of bss sections in bytes
|
||||
u32 relOffset;
|
||||
u32 impOffset;
|
||||
u32 impSize; // size in bytes
|
||||
u8 prologSection; // section # for prolog function
|
||||
u8 epilogSection; // section # for epilog function
|
||||
u8 unresolvedSection; // section # for unresolved function
|
||||
u8 bssSection; // section # for bss section (set at run-time)
|
||||
u32 prolog; // prolog function offset
|
||||
u32 epilog; // epilog function offset
|
||||
u32 unresolved; // unresolved function offset
|
||||
|
||||
// OS_MODULE_VERSION == 2
|
||||
#if (2 <= OS_MODULE_VERSION)
|
||||
u32 align; // module alignment constraint
|
||||
u32 bssAlign; // bss alignment constraint
|
||||
#endif
|
||||
|
||||
// OS_MODULE_VERSION == 3
|
||||
#if (3 <= OS_MODULE_VERSION)
|
||||
u32 fixSize;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define OSGetSectionInfo(module) ((OSSectionInfo*)(((OSModuleInfo*)(module))->sectionInfoOffset))
|
||||
|
||||
#define OS_SECTIONINFO_EXEC 0x1
|
||||
#define OS_SECTIONINFO_OFFSET(offset) ((offset) & ~0x1)
|
||||
|
||||
struct OSImportInfo {
|
||||
OSModuleID id; // external module id
|
||||
u32 offset; // offset to OSRel instructions
|
||||
};
|
||||
|
||||
struct OSRel {
|
||||
u16 offset; // byte offset from the previous entry
|
||||
u8 type;
|
||||
u8 section;
|
||||
u32 addend;
|
||||
};
|
||||
|
||||
#define R_DOLPHIN_NOP 201 // C9h current offset += OSRel.offset
|
||||
#define R_DOLPHIN_SECTION 202 // CAh current section = OSRel.section
|
||||
#define R_DOLPHIN_END 203 // CBh
|
||||
#define R_DOLPHIN_MRKREF 204 // CCh
|
||||
|
||||
BOOL OSLink(OSModuleInfo* newModule, void* bss);
|
||||
BOOL OSLinkFixed(OSModuleInfo* newModule, void* bss);
|
||||
BOOL OSUnlink(OSModuleInfo* module);
|
||||
void OSSetStringTable(const void* string_table);
|
||||
void __OSModuleInit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* OSLINK_H */
|
||||
@@ -7,63 +7,63 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct OSModuleInfo_s OSModuleInfo;
|
||||
// typedef struct OSModuleInfo_s OSModuleInfo;
|
||||
|
||||
typedef struct OSModuleQueue_s {
|
||||
OSModuleInfo* head;
|
||||
OSModuleInfo* tail;
|
||||
} OSModuleQueue;
|
||||
// typedef struct OSModuleQueue_s {
|
||||
// OSModuleInfo* head;
|
||||
// OSModuleInfo* tail;
|
||||
// } OSModuleQueue;
|
||||
|
||||
typedef struct OSModuleLink_s {
|
||||
OSModuleInfo* next;
|
||||
OSModuleInfo* prev;
|
||||
} OSModuleLink;
|
||||
// typedef struct OSModuleLink_s {
|
||||
// OSModuleInfo* next;
|
||||
// OSModuleInfo* prev;
|
||||
// } OSModuleLink;
|
||||
|
||||
typedef struct OSModuleInfo_s {
|
||||
u32 id;
|
||||
OSModuleLink link;
|
||||
u32 numSections;
|
||||
u32 sectionInfoOfs;
|
||||
u32 nameOfs;
|
||||
u32 nameSize;
|
||||
u32 version;
|
||||
} OSModuleInfo;
|
||||
// typedef struct OSModuleInfo_s {
|
||||
// u32 id;
|
||||
// OSModuleLink link;
|
||||
// u32 numSections;
|
||||
// u32 sectionInfoOfs;
|
||||
// u32 nameOfs;
|
||||
// u32 nameSize;
|
||||
// u32 version;
|
||||
// } OSModuleInfo;
|
||||
|
||||
typedef struct OSModuleHeader_s {
|
||||
OSModuleInfo info;
|
||||
u32 bssSize;
|
||||
u32 relOfs;
|
||||
u32 impOfs;
|
||||
u32 impSize;
|
||||
// typedef struct OSModuleHeader_s {
|
||||
// OSModuleInfo info;
|
||||
// u32 bssSize;
|
||||
// u32 relOfs;
|
||||
// u32 impOfs;
|
||||
// u32 impSize;
|
||||
|
||||
u8 prologSection;
|
||||
u8 epilogSection;
|
||||
u8 unresolvedSection;
|
||||
u8 bssSection;
|
||||
// u8 prologSection;
|
||||
// u8 epilogSection;
|
||||
// u8 unresolvedSection;
|
||||
// u8 bssSection;
|
||||
|
||||
u32 prolog;
|
||||
u32 epilog;
|
||||
u32 unresolved;
|
||||
/* OS_MODULE_VERSION >= 2 */
|
||||
// u32 prolog;
|
||||
// u32 epilog;
|
||||
// u32 unresolved;
|
||||
// /* OS_MODULE_VERSION >= 2 */
|
||||
|
||||
u32 align;
|
||||
u32 bssAlign;
|
||||
} OSModuleHeader;
|
||||
// u32 align;
|
||||
// u32 bssAlign;
|
||||
// } OSModuleHeader;
|
||||
|
||||
typedef struct OSSectionInfo_s {
|
||||
u32 offset;
|
||||
u32 size;
|
||||
} OSSectionInfo;
|
||||
// typedef struct OSSectionInfo_s {
|
||||
// u32 offset;
|
||||
// u32 size;
|
||||
// } OSSectionInfo;
|
||||
|
||||
#define OSGetSectionInfo(module) \
|
||||
((OSSectionInfo*) (((OSModuleInfo*) (module))->sectionInfoOfs))
|
||||
// #define OSGetSectionInfo(module) \
|
||||
// ((OSSectionInfo*) (((OSModuleInfo*) (module))->sectionInfoOfs))
|
||||
|
||||
#define OS_SECTIONINFO_EXEC 1
|
||||
#define OS_SECTIONINFO_OFFSET(offset) ((offset) & ~OS_SECTIONINFO_EXEC)
|
||||
// #define OS_SECTIONINFO_EXEC 1
|
||||
// #define OS_SECTIONINFO_OFFSET(offset) ((offset) & ~OS_SECTIONINFO_EXEC)
|
||||
|
||||
void OSSetStringTable (const void* strTable);
|
||||
BOOL OSLink(OSModuleInfo* module, void* bss);
|
||||
BOOL OSUnlink(OSModuleInfo* module);
|
||||
// void OSSetStringTable (const void* strTable);
|
||||
// BOOL OSLink(OSModuleInfo* module, void* bss);
|
||||
// BOOL OSUnlink(OSModuleInfo* module);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ extern "C" {
|
||||
#define OS_RESET_HOTRESET 1 /* Soft reset */
|
||||
#define OS_RESET_SHUTDOWN 2
|
||||
|
||||
struct OSResetFunctionQueue {
|
||||
struct OSResetFunctionInfo* head;
|
||||
struct OSResetFunctionInfo* tail;
|
||||
};
|
||||
|
||||
typedef BOOL (*OSResetFunction)(BOOL final);
|
||||
typedef struct OSResetFunctionInfo OSResetFunctionInfo;
|
||||
|
||||
|
||||
@@ -7,7 +7,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
BOOL OSGetResetSwitchState();
|
||||
typedef void (*OSResetCallback)(void);
|
||||
|
||||
OSResetCallback OSSetResetCallback(OSResetCallback callback);
|
||||
BOOL OSGetResetSwitchState(void);
|
||||
BOOL OSGetResetButtonState(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -46,6 +46,19 @@ typedef struct OSCalendarTime_s {
|
||||
OSTime OSCalendarTimeToTicks(OSCalendarTime* td);
|
||||
void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td);
|
||||
|
||||
#define USEC_MAX 1000
|
||||
#define MSEC_MAX 1000
|
||||
#define MONTH_MAX 12
|
||||
#define WEEK_DAY_MAX 7
|
||||
#define YEAR_DAY_MAX 365
|
||||
|
||||
#define SECS_IN_MIN 60
|
||||
#define SECS_IN_HOUR (SECS_IN_MIN * 60)
|
||||
#define SECS_IN_DAY (SECS_IN_HOUR * 24)
|
||||
#define SECS_IN_YEAR (SECS_IN_DAY * 365)
|
||||
|
||||
#define BIAS 0xB2575
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -187,7 +187,7 @@ bool JUTException::searchPartialModule(u32 address, u32* module_id, u32* section
|
||||
if (section_offset)
|
||||
*section_offset = address - addr;
|
||||
if (name_offset)
|
||||
*name_offset = module->nameOfs;
|
||||
*name_offset = module->nameOffset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ s32 search_partial_address(u32 addr, u32* module_id, u32* section_idx, u32* sect
|
||||
*section_addr = addr - section_ofs;
|
||||
}
|
||||
if (module_name_ofs != nullptr) {
|
||||
*module_name_ofs = module_p->info.nameOfs;
|
||||
*module_name_ofs = module_p->info.nameOffset;
|
||||
}
|
||||
|
||||
return 0; /* success */
|
||||
|
||||
@@ -0,0 +1,583 @@
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/base/PPCArch.h>
|
||||
#include <dolphin/db.h>
|
||||
#include <dolphin/exi.h>
|
||||
#include <string.h>
|
||||
#include <macros.h>
|
||||
#include "../src/static/dolphin/os/__os.h"
|
||||
|
||||
void EnableMetroTRKInterrupts(void);
|
||||
|
||||
#define OS_CURRENTCONTEXT_PADDR 0x00C0
|
||||
|
||||
#define OS_EXCEPTIONTABLE_ADDR 0x3000
|
||||
#define OS_DBJUMPPOINT_ADDR 0x60
|
||||
// memory locations for important stuff
|
||||
#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
|
||||
|
||||
extern unsigned long __DVDLongFileNameFlag;
|
||||
extern unsigned long __PADSpec;
|
||||
extern unsigned char __ArenaLo[];
|
||||
extern char _stack_addr[];
|
||||
extern unsigned char __ArenaHi[];
|
||||
|
||||
// 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
|
||||
|
||||
static OSBootInfo* BootInfo;
|
||||
static volatile u32* BI2DebugFlag;
|
||||
static u32* BI2DebugFlagHolder;
|
||||
static f64 ZeroPS;
|
||||
static f64 ZeroF;
|
||||
static BOOL __OSIsGcam;
|
||||
static BOOL AreWeInitialized;
|
||||
|
||||
typedef void (*OSExceptionHandler)(u8, struct OSContext*);
|
||||
static OSExceptionHandler* OSExceptionTable;
|
||||
|
||||
static void* __OSSavedRegionEnd;
|
||||
static void* __OSSavedRegionStart;
|
||||
static BOOL __OSInIPL;
|
||||
OSTime __OSStartTime;
|
||||
|
||||
static DVDDriveInfo DriveInfo __attribute__((aligned(0x20)));
|
||||
static DVDCommandBlock DriveBlock;
|
||||
|
||||
// functions
|
||||
static asm void __OSInitFPRs(void);
|
||||
static void OSExceptionInit(void);
|
||||
static void OSDefaultExceptionHandler(u8 exception /* r3 */,
|
||||
OSContext* context /* r4 */);
|
||||
|
||||
// NOTE: this is unused, but stuff won't align properly without it
|
||||
static asm void __OSInitFPRs(void)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x2000
|
||||
mtmsr r3
|
||||
|
||||
mfspr r3, 0x398
|
||||
rlwinm. r3, r3, 3, 0x1f, 0x1f
|
||||
beq skip_ps_init
|
||||
|
||||
lis r3, ZeroPS@ha
|
||||
addi r3, r3, ZeroPS@l
|
||||
psq_l f0, 0(r3), 0, 0
|
||||
ps_mr f1, f0
|
||||
ps_mr f2, f0
|
||||
ps_mr f3, f0
|
||||
ps_mr f4, f0
|
||||
ps_mr f5, f0
|
||||
ps_mr f6, f0
|
||||
ps_mr f7, f0
|
||||
ps_mr f8, f0
|
||||
ps_mr f9, f0
|
||||
ps_mr f10, f0
|
||||
ps_mr f11, f0
|
||||
ps_mr f12, f0
|
||||
ps_mr f13, f0
|
||||
ps_mr f14, f0
|
||||
ps_mr f15, f0
|
||||
ps_mr f16, f0
|
||||
ps_mr f17, f0
|
||||
ps_mr f18, f0
|
||||
ps_mr f19, f0
|
||||
ps_mr f20, f0
|
||||
ps_mr f21, f0
|
||||
ps_mr f22, f0
|
||||
ps_mr f23, f0
|
||||
ps_mr f24, f0
|
||||
ps_mr f25, f0
|
||||
ps_mr f26, f0
|
||||
ps_mr f27, f0
|
||||
ps_mr f28, f0
|
||||
ps_mr f29, f0
|
||||
ps_mr f30, f0
|
||||
ps_mr f31, f0
|
||||
|
||||
skip_ps_init:
|
||||
lfd f0, ZeroF(r13)
|
||||
fmr f1, f0
|
||||
fmr f2, f0
|
||||
fmr f3, f0
|
||||
fmr f4, f0
|
||||
fmr f5, f0
|
||||
fmr f6, f0
|
||||
fmr f7, f0
|
||||
fmr f8, f0
|
||||
fmr f9, f0
|
||||
fmr f10, f0
|
||||
fmr f11, f0
|
||||
fmr f12, f0
|
||||
fmr f13, f0
|
||||
fmr f14, f0
|
||||
fmr f15, f0
|
||||
fmr f16, f0
|
||||
fmr f17, f0
|
||||
fmr f18, f0
|
||||
fmr f19, f0
|
||||
fmr f20, f0
|
||||
fmr f21, f0
|
||||
fmr f22, f0
|
||||
fmr f23, f0
|
||||
fmr f24, f0
|
||||
fmr f25, f0
|
||||
fmr f26, f0
|
||||
fmr f27, f0
|
||||
fmr f28, f0
|
||||
fmr f29, f0
|
||||
fmr f30, f0
|
||||
fmr f31, f0
|
||||
|
||||
mtfsf 0xff, f0
|
||||
blr
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
unsigned long OSGetConsoleType()
|
||||
{
|
||||
if ((!BootInfo) || (BootInfo->consoleType == 0)) {
|
||||
return OS_CONSOLE_ARTHUR;
|
||||
}
|
||||
return BootInfo->consoleType;
|
||||
}
|
||||
|
||||
volatile u16 __OSDeviceCode AT_ADDRESS(0x800030E6);
|
||||
|
||||
static void ClearArena()
|
||||
{
|
||||
if (OSGetResetCode() != -0x80000000) {
|
||||
__OSSavedRegionStart = NULL;
|
||||
__OSSavedRegionEnd = NULL;
|
||||
memset(OSGetArenaLo(), 0, (u8*)OSGetArenaHi() - (u8*)OSGetArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
__OSSavedRegionStart = BOOT_REGION_START;
|
||||
__OSSavedRegionEnd = BOOT_REGION_END;
|
||||
|
||||
if (BOOT_REGION_START == NULL) {
|
||||
memset(OSGetArenaLo(), 0, (u8*)OSGetArenaHi() - (u8*)OSGetArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
if ((u8*)OSGetArenaLo() < (u8*)__OSSavedRegionStart) {
|
||||
if ((u8*)OSGetArenaHi() <= (u8*)__OSSavedRegionStart) {
|
||||
memset(OSGetArenaLo(), 0,
|
||||
(u8*)OSGetArenaHi() - (u8*)OSGetArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
memset(OSGetArenaLo(), 0,
|
||||
(u8*)__OSSavedRegionStart - (u8*)OSGetArenaLo());
|
||||
|
||||
if ((u8*)OSGetArenaHi() > (u8*)__OSSavedRegionEnd) {
|
||||
memset(__OSSavedRegionEnd, 0,
|
||||
(u8*)OSGetArenaHi() - (u8*)__OSSavedRegionEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void InquiryCallback(s32 result, struct DVDCommandBlock* block)
|
||||
{
|
||||
switch (block->state) {
|
||||
case 0:
|
||||
__OSDeviceCode = DriveInfo.deviceCode | 0x8000;
|
||||
break;
|
||||
default:
|
||||
__OSDeviceCode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OSInit()
|
||||
{
|
||||
u32 consoleType;
|
||||
BI2Debug* bi2DebugInfo;
|
||||
|
||||
if (AreWeInitialized != 0)
|
||||
return;
|
||||
|
||||
AreWeInitialized = 1;
|
||||
__OSStartTime = __OSGetSystemTime();
|
||||
OSDisableInterrupts();
|
||||
PPCDisableSpeculation();
|
||||
PPCSetFpNonIEEEMode();
|
||||
BootInfo = (struct OSBootInfo_s*)OSPhysicalToCached(0);
|
||||
BI2DebugFlag = NULL;
|
||||
__DVDLongFileNameFlag = 0;
|
||||
bi2DebugInfo = (BI2Debug*)*(BI2Debug**)OS_BI2_DEBUG_ADDRESS;
|
||||
if (bi2DebugInfo != NULL) {
|
||||
BI2DebugFlag = &bi2DebugInfo->debugFlag;
|
||||
__PADSpec = bi2DebugInfo->padSpec;
|
||||
*((u8*)DEBUGFLAG_ADDR) = (u8)*BI2DebugFlag;
|
||||
*((u8*)OS_DEBUG_ADDRESS_2) = (u8)__PADSpec;
|
||||
} else if (BootInfo->arenaHi) {
|
||||
BI2DebugFlagHolder = (u32*)*((u8*)DEBUGFLAG_ADDR);
|
||||
BI2DebugFlag = (u32*)&BI2DebugFlagHolder;
|
||||
__PADSpec = (u32) * ((u8*)OS_DEBUG_ADDRESS_2);
|
||||
}
|
||||
|
||||
__DVDLongFileNameFlag = 1;
|
||||
|
||||
OSSetArenaLo((!BootInfo->arenaLo) ? &__ArenaLo : BootInfo->arenaLo);
|
||||
if ((!BootInfo->arenaLo) && (BI2DebugFlag) && (*(u32*)BI2DebugFlag < 2)) {
|
||||
OSSetArenaLo((void*)(((u32)(char*)&_stack_addr + 0x1F) & 0xFFFFFFE0));
|
||||
}
|
||||
OSSetArenaHi((!BootInfo->arenaHi) ? &__ArenaHi : BootInfo->arenaHi);
|
||||
OSExceptionInit();
|
||||
__OSInitSystemCall();
|
||||
OSInitAlarm();
|
||||
__OSModuleInit();
|
||||
__OSInterruptInit();
|
||||
__OSSetInterruptHandler(0x16, &__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 (__OSInIPL == 0) {
|
||||
__OSInitMemoryProtection();
|
||||
}
|
||||
|
||||
OSReport("\nDolphin OS $Revision: 54 $.\n");
|
||||
OSReport("Kernel built : %s %s\n", "Jun 5 2002", "02:09:12");
|
||||
|
||||
OSReport("Console Type : ");
|
||||
|
||||
consoleType = OSGetConsoleType();
|
||||
// work out what console type this corresponds to and report it
|
||||
// consoleTypeSwitchHi = inputConsoleType & 0xF0000000;
|
||||
if ((consoleType & 0x10000000) == OS_CONSOLE_RETAIL) { // check "first" byte
|
||||
OSReport("Retail %d\n", consoleType);
|
||||
} else {
|
||||
switch (consoleType) { // 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)consoleType - 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());
|
||||
|
||||
// if location of debug flag exists, and flag is >= 2, enable
|
||||
// MetroTRKInterrupts
|
||||
if (BI2DebugFlag && ((*BI2DebugFlag) >= 2)) {
|
||||
EnableMetroTRKInterrupts();
|
||||
}
|
||||
ClearArena();
|
||||
OSEnableInterrupts();
|
||||
if (__OSInIPL == 0) {
|
||||
DVDInit();
|
||||
|
||||
if (__OSIsGcam) {
|
||||
__OSDeviceCode = 0x9000;
|
||||
return;
|
||||
}
|
||||
|
||||
DCInvalidateRange(&DriveInfo, 0x20);
|
||||
DVDInquiryAsync(&DriveBlock, &DriveInfo, InquiryCallback);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 __OSExceptionLocations[] = {
|
||||
0x00000100, 0x00000200, 0x00000300, 0x00000400, 0x00000500,
|
||||
0x00000600, 0x00000700, 0x00000800, 0x00000900, 0x00000C00,
|
||||
0x00000D00, 0x00000F00, 0x00001300, 0x00001400, 0x00001700,
|
||||
};
|
||||
|
||||
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)__OSDBJUMPSTART - (u32)__OSDBINTSTART);
|
||||
DCFlushRangeNoSync(destAddr,
|
||||
(u32)__OSDBJUMPSTART - (u32)__OSDBINTSTART);
|
||||
__sync();
|
||||
ICInvalidateRange(destAddr, (u32)__OSDBJUMPSTART - (u32)__OSDBINTSTART);
|
||||
}
|
||||
|
||||
// Copy the right vector into the table
|
||||
for (exception = 0; exception < __OS_EXCEPTION_MAX; 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*)__OSDBJUMPSTART,
|
||||
(u32)__OSDBJUMPEND - (u32)__OSDBJUMPSTART);
|
||||
} else {
|
||||
// make sure the opcodes are still nop
|
||||
u32* ops = (u32*)__DBVECTOR;
|
||||
int cb;
|
||||
|
||||
for (cb = 0; cb < (u32)__OSDBJUMPEND - (u32)__OSDBJUMPSTART;
|
||||
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 = (void*)OSPhysicalToCached(OS_EXCEPTIONTABLE_ADDR);
|
||||
|
||||
// install default exception handlers
|
||||
for (exception = 0; exception < __OS_EXCEPTION_MAX; 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)
|
||||
{
|
||||
#ifdef __MWERKS__ // 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
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
static asm void __OSDBJump(void) {
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
entry __OSDBJUMPSTART
|
||||
bla OS_DBJUMPPOINT_ADDR
|
||||
entry __OSDBJUMPEND
|
||||
#endif // 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)
|
||||
{
|
||||
#ifdef __MWERKS__ // 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
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
void __OSUnhandledException(__OSException exception, OSContext* context,
|
||||
u32 dsisr, u32 dar);
|
||||
asm void OSDefaultExceptionHandler(register __OSException exception,
|
||||
register OSContext* context)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
OS_EXCEPTION_SAVE_GPRS(context)
|
||||
mfdsisr r5
|
||||
mfdar r6
|
||||
stwu r1, -0x8(r1)
|
||||
b __OSUnhandledException
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
void __OSPSInit(void)
|
||||
{
|
||||
PPCMthid2(PPCMfhid2() | 0x80000000 | 0x20000000);
|
||||
ICFlashInvalidate();
|
||||
__sync();
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
asm
|
||||
{
|
||||
li r3, 0
|
||||
mtspr GQR0, r3
|
||||
}
|
||||
#endif // 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);
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/base/PPCArch.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <macros.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 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;
|
||||
}
|
||||
|
||||
void* OSAllocFromHeap(int heap, unsigned long size)
|
||||
{
|
||||
struct HeapDesc* hd;
|
||||
struct Cell* cell;
|
||||
struct Cell* newCell;
|
||||
long leftoverSize;
|
||||
long requested;
|
||||
|
||||
requested = size;
|
||||
ASSERTMSGLINE(0x14D, HeapArray,
|
||||
"OSAllocFromHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(0x14E, (signed long)size > 0,
|
||||
"OSAllocFromHeap(): invalid size.");
|
||||
ASSERTMSGLINE(0x14F, heap >= 0 && heap < NumHeaps,
|
||||
"OSAllocFromHeap(): invalid heap handle.");
|
||||
ASSERTMSGLINE(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;
|
||||
}
|
||||
ASSERTMSGLINE(0x168, !((s32)cell & 0x1F),
|
||||
"OSAllocFromHeap(): heap is broken.");
|
||||
ASSERTMSGLINE(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 {
|
||||
ASSERTMSGLINE(0x186, hd->free == cell,
|
||||
"OSAllocFromHeap(): heap is broken.");
|
||||
hd->free = newCell;
|
||||
}
|
||||
}
|
||||
|
||||
hd->allocated = DLAddFront(hd->allocated, cell);
|
||||
return (u8*)cell + 0x20;
|
||||
}
|
||||
|
||||
void OSFreeToHeap(int heap, void* ptr)
|
||||
{
|
||||
struct HeapDesc* hd;
|
||||
struct Cell* cell;
|
||||
|
||||
ASSERTMSGLINE(0x23D, HeapArray, "OSFreeToHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(
|
||||
0x23F, ((u32)ArenaStart + 0x20) <= (u32)ptr && (u32)ptr < (u32)ArenaEnd,
|
||||
"OSFreeToHeap(): invalid pointer.");
|
||||
ASSERTMSGLINE(0x240, OFFSET(ptr, ALIGNMENT) == 0,
|
||||
"OSFreeToHeap(): invalid pointer.");
|
||||
ASSERTMSGLINE(0x241, HeapArray[heap].size >= 0,
|
||||
"OSFreeToHeap(): invalid heap handle.");
|
||||
cell = (void*)((u32)ptr - 0x20);
|
||||
hd = &HeapArray[heap];
|
||||
ASSERTMSGLINE(0x246, cell->hd == hd, "OSFreeToHeap(): invalid pointer.");
|
||||
ASSERTMSGLINE(0x247, DLLookup(hd->allocated, cell),
|
||||
"OSFreeToHeap(): invalid pointer.");
|
||||
|
||||
hd->allocated = DLExtract(hd->allocated, cell);
|
||||
hd->free = DLInsert(hd->free, cell);
|
||||
}
|
||||
|
||||
void* OSInitAlloc(void* arenaStart, void* arenaEnd, int maxHeaps)
|
||||
{
|
||||
unsigned long arraySize;
|
||||
int i;
|
||||
struct HeapDesc* hd;
|
||||
|
||||
ASSERTMSGLINE(0x283, maxHeaps > 0,
|
||||
"OSInitAlloc(): invalid number of heaps.");
|
||||
ASSERTMSGLINE(0x285, (u32)arenaStart < (u32)arenaEnd,
|
||||
"OSInitAlloc(): invalid range.");
|
||||
ASSERTMSGLINE(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);
|
||||
ASSERTMSGLINE(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;
|
||||
|
||||
ASSERTMSGLINE(0x2BD, HeapArray, "OSCreateHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(0x2BE, (u32)start < (u32)end,
|
||||
"OSCreateHeap(): invalid range.");
|
||||
|
||||
start = (void*)(((u32)start + 0x1FU) & ~((32) - 1));
|
||||
end = (void*)(((u32)end) & ~((32) - 1));
|
||||
|
||||
ASSERTMSGLINE(0x2C1, (u32)start < (u32)end,
|
||||
"OSCreateHeap(): invalid range.");
|
||||
ASSERTMSGLINE(0x2C3,
|
||||
(u32)ArenaStart <= (u32)start && (u32)end <= (u32)ArenaEnd,
|
||||
"OSCreateHeap(): invalid range.");
|
||||
ASSERTMSGLINE(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;
|
||||
|
||||
ASSERTMSGLINE(0x30A, HeapArray,
|
||||
"OSDestroyHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(0x30B, (heap >= 0) && (heap < NumHeaps),
|
||||
"OSDestroyHeap(): invalid heap handle.");
|
||||
ASSERTMSGLINE(0x30C, HeapArray[heap].size >= 0,
|
||||
"OSDestroyHeap(): invalid heap handle.");
|
||||
|
||||
hd = &HeapArray[heap];
|
||||
|
||||
hd->size = -1;
|
||||
}
|
||||
|
||||
// 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);
|
||||
// NOTE: macro arg is stringified so format mustn't touch it
|
||||
// clang-format off
|
||||
ASSERTREPORT(0x39D, cell->next == NULL
|
||||
|| (char*) cell + cell->size < (char*) cell->next);
|
||||
// clang-format on
|
||||
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;
|
||||
|
||||
ASSERTMSGLINE(0x3BB, HeapArray,
|
||||
"OSReferentSize(): heap is not initialized.");
|
||||
ASSERTMSGLINE(0x3BD, InRange(ptr, ArenaStart + HEADERSIZE, ArenaEnd),
|
||||
"OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(0x3BE, !OFFSET(ptr, 32),
|
||||
"OSReferentSize(): invalid pointer.");
|
||||
cell = (void*)((u32)ptr - HEADERSIZE);
|
||||
ASSERTMSGLINE(0x3C2, cell->hd, "OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(0x3C4, !(((u32)cell->hd - (u32)HeapArray) % 24),
|
||||
"OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(
|
||||
0x3C6,
|
||||
((u32)HeapArray <= (u32)cell->hd)
|
||||
&& ((u32)cell->hd < (u32)((u32)HeapArray + (NumHeaps * 0x18))),
|
||||
"OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(0x3C7, cell->hd->size >= 0,
|
||||
"OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(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);
|
||||
ASSERTMSGLINE(0x3DE, HeapArray, "OSDumpHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(0x3DF, (heap >= 0) && (heap < NumHeaps),
|
||||
"OSDumpHeap(): invalid heap handle.");
|
||||
hd = &HeapArray[heap];
|
||||
if (hd->size < 0) {
|
||||
OSReport("--------Inactive\n");
|
||||
return;
|
||||
}
|
||||
ASSERTMSGLINE(0x3E8, OSCheckHeap(heap) >= 0,
|
||||
"OSDumpHeap(): heap is broken.");
|
||||
|
||||
OSReport("addr size end prev next\n");
|
||||
OSReport("--------Allocated\n");
|
||||
|
||||
ASSERTMSGLINE(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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,505 @@
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <macros.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
|
||||
static OSFontHeader* FontData; // type unsure
|
||||
static u8* SheetImage; // type unsure
|
||||
static u8* WidthTable; // type unsure
|
||||
static int CharsInSheet; // type unsure
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned short 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;
|
||||
}
|
||||
|
||||
static void ExpandFontSheet(u8* src, u8* dst)
|
||||
{
|
||||
int i;
|
||||
u8* colorIndex = &FontData->c0;
|
||||
|
||||
if (FontData->sheetFormat == GX_TF_I4) {
|
||||
for (i = (s32)(FontData->sheetFullSize) / 2 - 1; i >= 0; i--) {
|
||||
dst[i * 2 + 0] = colorIndex[src[i] >> 6 & 3] & 0xF0
|
||||
| colorIndex[src[i] >> 4 & 3] & 0x0F;
|
||||
dst[i * 2 + 1] = colorIndex[src[i] >> 2 & 3] & 0xF0
|
||||
| colorIndex[src[i] >> 0 & 3] & 0x0F;
|
||||
}
|
||||
} else if (FontData->sheetFormat == GX_TF_IA4) {
|
||||
for (i = (s32)(FontData->sheetFullSize) / 4 - 1; i >= 0; i--) {
|
||||
dst[i * 4 + 0] = colorIndex[src[i] >> 6 & 3];
|
||||
dst[i * 4 + 1] = colorIndex[src[i] >> 4 & 3];
|
||||
dst[i * 4 + 2] = colorIndex[src[i] >> 2 & 3];
|
||||
dst[i * 4 + 3] = colorIndex[src[i] >> 0 & 3];
|
||||
}
|
||||
}
|
||||
|
||||
DCStoreRange(dst, FontData->sheetFullSize);
|
||||
}
|
||||
|
||||
int OSInitFont(OSFontHeader* fontData)
|
||||
{
|
||||
unsigned long size;
|
||||
void* temp;
|
||||
|
||||
if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) {
|
||||
temp = (void*)((u8*)fontData + 0xD3F00);
|
||||
} else {
|
||||
temp = (void*)((u8*)fontData + 0x1D120);
|
||||
}
|
||||
temp = ((void*)(((u32)(temp)) & ~((32) - 1)));
|
||||
size = OSLoadFont(fontData, temp);
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
SheetImage = (u8*)FontData + FontData->sheetImage;
|
||||
SheetImage = (void*)((s32)(SheetImage + 0x1F) & 0xFFFFFFE0);
|
||||
ExpandFontSheet((u8*)FontData + FontData->sheetImage, SheetImage);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* OSGetFontTexture(char* string, void** image, long* x, long* y,
|
||||
long* width)
|
||||
{
|
||||
unsigned short code;
|
||||
int fontCode;
|
||||
int sheet;
|
||||
int numChars;
|
||||
int row;
|
||||
int column;
|
||||
|
||||
ASSERTLINE(0x291, SheetImage);
|
||||
ASSERTLINE(0x292, WidthTable);
|
||||
|
||||
code = *string;
|
||||
if (code == 0) {
|
||||
*image = NULL;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
fontCode = GetFontCode(code);
|
||||
|
||||
sheet = fontCode / CharsInSheet;
|
||||
((u32*)image)[0] = (u32)SheetImage + (FontData->sheetSize * sheet);
|
||||
numChars = fontCode - (sheet * CharsInSheet);
|
||||
row = numChars / FontData->sheetColumn;
|
||||
column = (numChars - (row * FontData->sheetColumn));
|
||||
*x = column * FontData->cellWidth;
|
||||
*y = row * FontData->cellHeight;
|
||||
|
||||
if (width) {
|
||||
*width = WidthTable[fontCode];
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
char* OSGetFontWidth(char* string, s32* width)
|
||||
{
|
||||
unsigned short code;
|
||||
|
||||
ASSERTLINE(0x2C2, WidthTable);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
*width = WidthTable[GetFontCode(code)];
|
||||
return string;
|
||||
}
|
||||
@@ -1,43 +1,424 @@
|
||||
#include "dolphin/os/OSInterrupt.h"
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <macros.h>
|
||||
#include <string.h>
|
||||
|
||||
asm BOOL OSDisableInterrupts(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
#include "../src/static/dolphin/os/__os.h"
|
||||
|
||||
entry __RAS_OSDisableInterrupts_begin
|
||||
mfmsr r3
|
||||
rlwinm r4, r3, 0, 17, 15
|
||||
mtmsr r4
|
||||
entry __RAS_OSDisableInterrupts_end
|
||||
rlwinm r3, r3, 17, 31, 31
|
||||
blr
|
||||
// clang-format on
|
||||
static asm void ExternalInterruptHandler(register __OSException exception,
|
||||
register OSContext* context);
|
||||
|
||||
extern void __RAS_OSDisableInterrupts_begin(void);
|
||||
extern void __RAS_OSDisableInterrupts_end(void);
|
||||
|
||||
static __OSInterruptHandler* InterruptHandlerTable;
|
||||
|
||||
volatile OSTime __OSLastInterruptTime;
|
||||
volatile __OSInterrupt __OSLastInterrupt;
|
||||
volatile u32 __OSLastInterruptSrr0;
|
||||
|
||||
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)
|
||||
{
|
||||
#ifdef __MWERKS__ // 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
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
asm BOOL OSEnableInterrupts(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
/* 8007AC38 7C6000A6 */ mfmsr r3
|
||||
/* 8007AC3C 60648000 */ ori r4, r3, 0x8000
|
||||
/* 8007AC40 7C800124 */ mtmsr r4
|
||||
/* 8007AC44 54638FFE */ rlwinm r3, r3, 0x11, 0x1f, 0x1f
|
||||
/* 8007AC48 4E800020 */ blr
|
||||
// clang-format on
|
||||
asm BOOL OSEnableInterrupts(void)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
|
||||
mfmsr r3
|
||||
ori r4, r3, 0x8000
|
||||
mtmsr r4
|
||||
rlwinm r3, r3, 17, 31, 31
|
||||
blr
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
asm BOOL OSRestoreInterrupts(register BOOL level) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
/* 8007AC4C 2C030000 */ cmpwi level, 0x0
|
||||
/* 8007AC50 7C8000A6 */ mfmsr r4
|
||||
/* 8007AC54 4182000C */ beq- lbl_8007ac60
|
||||
/* 8007AC58 60858000 */ ori r5, r4, 0x8000
|
||||
/* 8007AC5C 48000008 */ b lbl_8007ac64
|
||||
lbl_8007ac60:
|
||||
/* 8007AC60 5485045E */ rlwinm r5, r4, 0, 0x11, 0xf
|
||||
lbl_8007ac64:
|
||||
/* 8007AC64 7CA00124 */ mtmsr r5
|
||||
/* 8007AC68 54838FFE */ rlwinm r3, r4, 0x11, 0x1f, 0x1f
|
||||
/* 8007AC6C 4E800020 */ blr
|
||||
// clang-format on
|
||||
}
|
||||
#ifdef __MWERKS__ // 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
|
||||
#endif // 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 = (void*)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);
|
||||
}
|
||||
|
||||
static 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 __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;
|
||||
}
|
||||
|
||||
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 (interrupt > __OS_INTERRUPT_MEM_ADDRESS) {
|
||||
__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)
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
OS_EXCEPTION_SAVE_GPRS(context)
|
||||
stwu r1, -0x8(r1)
|
||||
b __OSDispatchInterrupt
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/os/OSLink.h>
|
||||
|
||||
#include "os/__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
|
||||
|
||||
#define ENQUEUE_INFO(queue, info, link) \
|
||||
do { \
|
||||
OSModuleInfo* __prev; \
|
||||
\
|
||||
__prev = (queue)->tail; \
|
||||
if (__prev == NULL) \
|
||||
(queue)->head = (info); \
|
||||
else \
|
||||
__prev->link.next = (info); \
|
||||
(info)->link.prev = __prev; \
|
||||
(info)->link.next = NULL; \
|
||||
(queue)->tail = (info); \
|
||||
} while (0)
|
||||
|
||||
#define DEQUEUE_INFO(info, queue, link) \
|
||||
do { \
|
||||
OSModuleInfo* __next; \
|
||||
OSModuleInfo* __prev; \
|
||||
\
|
||||
__next = (info)->link.next; \
|
||||
__prev = (info)->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)
|
||||
|
||||
OSModuleQueue __OSModuleInfoList AT_ADDRESS(OS_BASE_CACHED | 0x30C8);
|
||||
|
||||
#pragma dont_inline on
|
||||
|
||||
__declspec(weak) void OSNotifyLink(void) {}
|
||||
__declspec(weak) void OSNotifyUnlink() {}
|
||||
|
||||
#pragma dont_inline reset
|
||||
|
||||
void OSSetStringTable(const void* string_table) {
|
||||
__OSStringTable = string_table;
|
||||
}
|
||||
|
||||
static BOOL Relocate(OSModuleHeader* newModule, OSModuleHeader* module) {
|
||||
u32 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;
|
||||
}
|
||||
BOOL OSLink(OSModuleInfo* newModule, void* bss) {
|
||||
u32 i;
|
||||
OSSectionInfo* si;
|
||||
OSModuleHeader* moduleHeader;
|
||||
OSModuleInfo* moduleInfo;
|
||||
OSImportInfo* imp;
|
||||
|
||||
moduleHeader = (OSModuleHeader*)newModule;
|
||||
|
||||
if (newModule->version > 2 || (newModule->version >= 2 &&
|
||||
((moduleHeader->align && (u32)newModule % moduleHeader->align != 0) ||
|
||||
(moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0))))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ENQUEUE_INFO(&__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;
|
||||
}
|
||||
|
||||
static BOOL Undo(OSModuleHeader* newModule, OSModuleHeader* module) {
|
||||
u32 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;
|
||||
u32 i;
|
||||
|
||||
moduleHeader = (OSModuleHeader*)oldModule;
|
||||
|
||||
DEQUEUE_INFO(oldModule, &__OSModuleInfoList, link);
|
||||
|
||||
for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
|
||||
Undo(moduleHeader, (OSModuleHeader*)moduleInfo);
|
||||
}
|
||||
|
||||
OSNotifyUnlink();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void __OSModuleInit(void) {
|
||||
__OSModuleList.tail = NULL;
|
||||
__OSModuleList.head = NULL;
|
||||
__OSStringTable = NULL;
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
#include <dolphin/os.h>
|
||||
#include "dolphin/os/OSMemory.h"
|
||||
#include "dolphin/os/OSError.h"
|
||||
#include "dolphin/os/OSInterrupt.h"
|
||||
#include "dolphin/hw_regs.h"
|
||||
#include "dolphin/os/OSReset.h"
|
||||
|
||||
#define TRUNC(n, a) (((u32)(n)) & ~((a)-1))
|
||||
#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1))
|
||||
|
||||
u32 OSGetConsoleSimulatedMemSize(void){
|
||||
return(SIM_MEM);
|
||||
}
|
||||
|
||||
static BOOL OnReset(BOOL final){
|
||||
if (final) {
|
||||
__MEMRegs[8] = 0xff;
|
||||
@@ -13,6 +19,7 @@ static BOOL OnReset(BOOL final){
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext* ctx){
|
||||
u32 cause = __MEMRegs[0xf];
|
||||
u32 addr = (((u32) __MEMRegs[0x12] & 0x3ff) << 16) | __MEMRegs[0x11];
|
||||
@@ -22,5 +29,185 @@ static void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext* ctx){
|
||||
__OSErrorTable[OS_ERROR_PROTECTION](OS_ERROR_PROTECTION, ctx, cause, addr);
|
||||
return;
|
||||
}
|
||||
__OSUnhandledException(OS_ERROR_PROTECTION, ctx, cause, addr);
|
||||
}
|
||||
|
||||
__OSUnhandledException(OS_ERROR_PROTECTION, ctx, cause, addr);
|
||||
}
|
||||
|
||||
#define OS_PROTECT_CONTROL_NONE 0x00
|
||||
#define OS_PROTECT_CONTROL_READ 0x01
|
||||
#define OS_PROTECT_CONTROL_WRITE 0x02
|
||||
#define OS_PROTECT_CONTROL_RDWR \
|
||||
(OS_PROTECT_CONTROL_READ | OS_PROTECT_CONTROL_WRITE)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static asm void Config24MB(void)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
|
||||
li r7, 0
|
||||
lis r4, 0x0000
|
||||
addi r4, r4, 0x0002
|
||||
lis r3, 0x8000
|
||||
addi r3, r3, 0x01FF
|
||||
lis r6, 0x0100
|
||||
addi r6, r6, 0x0002
|
||||
lis r5, 0x8100
|
||||
addi r5, r5, 0x00FF
|
||||
isync
|
||||
mtdbatu 0, r7
|
||||
mtdbatl 0, r4
|
||||
mtdbatu 0, r3
|
||||
isync
|
||||
mtibatu 0, r7
|
||||
mtibatl 0, r4
|
||||
mtibatu 0, r3
|
||||
isync
|
||||
mtdbatu 2, r7
|
||||
mtdbatl 2, r6
|
||||
mtdbatu 2, r5
|
||||
isync
|
||||
mtibatu 2, r7
|
||||
mtibatl 2, r6
|
||||
mtibatu 2, r5
|
||||
isync
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtspr 0x1b, r3
|
||||
mflr r3
|
||||
mtspr 0x1a, r3
|
||||
rfi
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
static asm void Config48MB(void)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
|
||||
li r7, 0
|
||||
lis r4, 0x0000
|
||||
addi r4, r4, 0x0002
|
||||
lis r3, 0x8000
|
||||
addi r3, r3, 0x03FF
|
||||
lis r6, 0x0200
|
||||
addi r6, r6, 0x0002
|
||||
lis r5, 0x8200
|
||||
addi r5, r5, 0x01FF
|
||||
isync
|
||||
mtdbatu 0, r7
|
||||
mtdbatl 0, r4
|
||||
mtdbatu 0, r3
|
||||
isync
|
||||
mtibatu 0, r7
|
||||
mtibatl 0, r4
|
||||
mtibatu 0, r3
|
||||
isync
|
||||
mtdbatu 2, r7
|
||||
mtdbatl 2, r6
|
||||
mtdbatu 2, r5
|
||||
isync
|
||||
mtibatu 2, r7
|
||||
mtibatl 2, r6
|
||||
mtibatu 2, r5
|
||||
isync
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtspr 0x1b, r3
|
||||
mflr r3
|
||||
mtspr 0x1a, r3
|
||||
rfi
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
static asm void RealMode(register u32 config)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
|
||||
clrlwi config, config, 2
|
||||
mtspr 0x1a, config
|
||||
mfmsr config
|
||||
rlwinm config, config, 0, 0x1c, 0x19
|
||||
mtspr 0x1b, config
|
||||
rfi
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
static OSResetFunctionInfo ResetFunctionInfo = {
|
||||
OnReset,
|
||||
0x7F,
|
||||
};
|
||||
|
||||
u32 OSGetPhysicalMemSize() { return __OSPhysicalMemSize; }
|
||||
|
||||
void __OSInitMemoryProtection()
|
||||
{
|
||||
char padding[0x28]; // TODO: wtf is this?
|
||||
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);
|
||||
|
||||
simulatedSize = OSGetConsoleSimulatedMemSize();
|
||||
if (simulatedSize < OSGetPhysicalMemSize() && simulatedSize == 0x1800000) {
|
||||
__MEMRegs[20] = 2;
|
||||
}
|
||||
|
||||
__OSUnmaskInterrupts(OS_INTERRUPTMASK_MEM_ADDRESS);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
void OSInitMessageQueue(struct OSMessageQueue* mq, OSMessage* msgArray,
|
||||
int msgCount)
|
||||
{
|
||||
OSInitThreadQueue(&mq->queueSend);
|
||||
OSInitThreadQueue(&mq->queueReceive);
|
||||
mq->msgArray = msgArray;
|
||||
mq->msgCount = msgCount;
|
||||
mq->firstIndex = 0;
|
||||
mq->usedCount = 0;
|
||||
}
|
||||
|
||||
int OSSendMessage(struct OSMessageQueue* mq, OSMessage msg, int flags)
|
||||
{
|
||||
int enabled;
|
||||
long lastIndex;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
while (mq->msgCount <= mq->usedCount) {
|
||||
if (!(flags & 1)) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
OSSleepThread(&mq->queueSend);
|
||||
}
|
||||
lastIndex = (mq->firstIndex + mq->usedCount) % mq->msgCount;
|
||||
((u32*)mq->msgArray)[lastIndex] = (u32)msg;
|
||||
mq->usedCount++;
|
||||
OSWakeupThread(&mq->queueReceive);
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSReceiveMessage(struct OSMessageQueue* mq, OSMessage* msg, int flags)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
|
||||
while (mq->usedCount == 0) {
|
||||
if (!(flags & 1)) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
OSSleepThread(&mq->queueReceive);
|
||||
}
|
||||
if (msg != NULL) {
|
||||
*(u32*)msg = ((u32*)mq->msgArray)[mq->firstIndex];
|
||||
}
|
||||
|
||||
mq->firstIndex = (mq->firstIndex + 1) % mq->msgCount;
|
||||
mq->usedCount--;
|
||||
OSWakeupThread(&mq->queueSend);
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSJamMessage(struct OSMessageQueue * mq, OSMessage msg, int flags) {
|
||||
int enabled = OSDisableInterrupts();
|
||||
|
||||
while(mq->msgCount <= mq->usedCount) {
|
||||
if(!(flags & 1)) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
OSSleepThread(&mq->queueSend);
|
||||
}
|
||||
mq->firstIndex = (mq->firstIndex + mq->msgCount - 1) % mq->msgCount;
|
||||
((u32*)mq->msgArray)[mq->firstIndex] = (u32)msg;
|
||||
mq->usedCount++;
|
||||
OSWakeupThread(&mq->queueReceive);
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <macros.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
|
||||
#define ENQUEUE_MUTEX(mutex, queue, link) \
|
||||
do { \
|
||||
struct OSMutex* __prev = (queue)->tail; \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = (mutex); \
|
||||
} else { \
|
||||
__prev->link.next = (mutex); \
|
||||
} \
|
||||
(mutex)->link.prev = __prev; \
|
||||
(mutex)->link.next = 0; \
|
||||
(queue)->tail = (mutex); \
|
||||
} while (0);
|
||||
|
||||
#define DEQUEUE_MUTEX(mutex, queue, link) \
|
||||
do { \
|
||||
struct OSMutex* __next = (mutex)->link.next; \
|
||||
struct OSMutex* __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);
|
||||
|
||||
#define DEQUEUE_HEAD(mutex, queue, link) \
|
||||
do { \
|
||||
struct OSMutex* __next = mutex->link.next; \
|
||||
if (__next == NULL) { \
|
||||
(queue)->tail = 0; \
|
||||
} else { \
|
||||
__next->link.prev = 0; \
|
||||
} \
|
||||
(queue)->head = __next; \
|
||||
} while (0);
|
||||
|
||||
void OSInitMutex(struct OSMutex* mutex)
|
||||
{
|
||||
OSInitThreadQueue(&mutex->queue);
|
||||
mutex->thread = 0;
|
||||
mutex->count = 0;
|
||||
}
|
||||
|
||||
void OSLockMutex(struct OSMutex* mutex)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
struct OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(0x8C, currentThread,
|
||||
"OSLockMutex(): current thread does not exist.");
|
||||
ASSERTMSGLINE(0x8E, currentThread->state == 2,
|
||||
"OSLockMutex(): current thread is not running.");
|
||||
|
||||
while (1) {
|
||||
struct OSThread* ownerThread = mutex->thread;
|
||||
if (ownerThread == 0) {
|
||||
mutex->thread = currentThread;
|
||||
mutex->count++;
|
||||
ENQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link);
|
||||
break;
|
||||
} else if (ownerThread == currentThread) {
|
||||
mutex->count++;
|
||||
break;
|
||||
} else {
|
||||
currentThread->mutex = mutex;
|
||||
__OSPromoteThread(mutex->thread, currentThread->priority);
|
||||
OSSleepThread(&mutex->queue);
|
||||
currentThread->mutex = NULL;
|
||||
}
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSUnlockMutex(struct OSMutex* mutex)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
struct OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(0xBD, currentThread,
|
||||
"OSUnlockMutex(): current thread does not exist.");
|
||||
ASSERTMSGLINE(0xBF, currentThread->state == 2,
|
||||
"OSUnlockMutex(): current thread is not running.");
|
||||
ASSERTMSG2LINE(
|
||||
0xC2, mutex->thread == currentThread,
|
||||
"OSUnlockMutex(): current thread %p is not the owner of mutex %p.",
|
||||
currentThread, mutex);
|
||||
|
||||
if (mutex->thread == currentThread) {
|
||||
if (!--mutex->count) {
|
||||
DEQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link);
|
||||
mutex->thread = 0;
|
||||
|
||||
if (currentThread->priority < currentThread->base) {
|
||||
currentThread->priority
|
||||
= __OSGetEffectivePriority(currentThread);
|
||||
}
|
||||
OSWakeupThread(&mutex->queue);
|
||||
}
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void __OSUnlockAllMutex(struct OSThread* thread)
|
||||
{
|
||||
struct OSMutex* mutex;
|
||||
|
||||
while (thread->queueMutex.head) {
|
||||
mutex = thread->queueMutex.head;
|
||||
DEQUEUE_HEAD(mutex, &thread->queueMutex, link);
|
||||
ASSERTLINE(0xE5, mutex->thread == thread);
|
||||
mutex->count = 0;
|
||||
mutex->thread = 0;
|
||||
OSWakeupThread(&mutex->queue);
|
||||
}
|
||||
}
|
||||
|
||||
int OSTryLockMutex(struct OSMutex* mutex)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
struct OSThread* currentThread = OSGetCurrentThread();
|
||||
int locked;
|
||||
|
||||
ASSERTMSGLINE(0xFF, currentThread,
|
||||
"OSTryLockMutex(): current thread does not exist.");
|
||||
ASSERTMSGLINE(0x101, currentThread->state == 2,
|
||||
"OSTryLockMutex(): current thread is not running.");
|
||||
|
||||
if (!mutex->thread) {
|
||||
mutex->thread = currentThread;
|
||||
mutex->count++;
|
||||
ENQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link);
|
||||
locked = 1;
|
||||
} else if (mutex->thread == currentThread) {
|
||||
mutex->count++;
|
||||
locked = 1;
|
||||
} else {
|
||||
locked = 0;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return locked;
|
||||
}
|
||||
|
||||
void OSInitCond(struct OSCond* cond) { OSInitThreadQueue(&cond->queue); }
|
||||
|
||||
void OSWaitCond(struct OSCond* cond, struct OSMutex* mutex)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
struct OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(0x139, currentThread,
|
||||
"OSWaitCond(): current thread does not exist.");
|
||||
ASSERTMSGLINE(0x13B, currentThread->state == 2,
|
||||
"OSWaitCond(): current thread is not running.");
|
||||
ASSERTMSG2LINE(
|
||||
0x13E, mutex->thread == currentThread,
|
||||
"OSWaitCond(): current thread %p is not the owner of mutex %p.",
|
||||
currentThread, mutex);
|
||||
|
||||
if (mutex->thread == currentThread) {
|
||||
long count = mutex->count;
|
||||
mutex->count = 0;
|
||||
DEQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link);
|
||||
mutex->thread = 0;
|
||||
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(struct OSCond* cond) { OSWakeupThread(&cond->queue); }
|
||||
|
||||
int __OSCheckMutex(struct OSMutex * mutex) {
|
||||
struct OSThread * thread;
|
||||
struct OSThreadQueue * queue;
|
||||
long priority;
|
||||
|
||||
priority = 0;
|
||||
queue = &mutex->queue;
|
||||
|
||||
if (queue->head != NULL && queue->head->link.prev != NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (queue->tail != NULL && queue->tail->link.next != NULL) {
|
||||
return 0;
|
||||
}
|
||||
thread = queue->head;
|
||||
while(thread) {
|
||||
if (thread->link.next != NULL && (thread != thread->link.next->link.prev)) {
|
||||
return 0;
|
||||
}
|
||||
if (thread->link.prev != NULL && (thread != thread->link.prev->link.next)) {
|
||||
return 0;
|
||||
}
|
||||
if (thread->state != 4) {
|
||||
return 0;
|
||||
}
|
||||
if (thread->priority < priority) {
|
||||
return 0;
|
||||
}
|
||||
priority = thread->priority;
|
||||
thread = thread->link.next;
|
||||
}
|
||||
if (mutex->thread) {
|
||||
if (mutex->count <= 0) {
|
||||
return 0;
|
||||
}
|
||||
} else if (mutex->count != 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int __OSCheckDeadLock(struct OSThread * thread) {
|
||||
struct OSMutex * mutex = thread->mutex;
|
||||
|
||||
while(mutex && mutex->thread) {
|
||||
if (mutex->thread == thread) {
|
||||
return 1;
|
||||
}
|
||||
mutex = mutex->thread->mutex;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __OSCheckMutexes(struct OSThread * thread) {
|
||||
struct OSMutex * mutex = thread->queueMutex.head;
|
||||
|
||||
while(mutex) {
|
||||
if (mutex->thread != thread) {
|
||||
return 0;
|
||||
}
|
||||
if (__OSCheckMutex(mutex) == 0) {
|
||||
return 0;
|
||||
}
|
||||
mutex = mutex->link.next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include "dvd/__dvd.h"
|
||||
#include "os/__os.h"
|
||||
|
||||
static void* SaveStart = NULL;
|
||||
static void* SaveEnd = NULL;
|
||||
static volatile BOOL Prepared;
|
||||
|
||||
extern u32 OS_RESET_CODE AT_ADDRESS(0x800030F0);
|
||||
// unknown function, set to true by __OSReboot
|
||||
extern u8 OS_REBOOT_BOOL AT_ADDRESS(0x800030E2);
|
||||
extern u32 UNK_817FFFF8 AT_ADDRESS(0x817FFFF8);
|
||||
extern u32 UNK_817FFFFC AT_ADDRESS(0x817FFFFC);
|
||||
|
||||
#define OS_BOOTROM_ADDR ((void*)0x81300000)
|
||||
|
||||
typedef struct _ApploaderHeader {
|
||||
/* 0x00 */ char date[16];
|
||||
/* 0x10 */ u32 entry;
|
||||
/* 0x14 */ u32 size;
|
||||
/* 0x18 */ u32 rebootSize;
|
||||
/* 0x1C */ u32 reserved2;
|
||||
} ApploaderHeader; // Size: 0x20
|
||||
|
||||
static ApploaderHeader Header __attribute__((aligned(32)));
|
||||
|
||||
static asm void Run(register void (*addr)())
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
fralloc
|
||||
bl OSDisableInterrupts
|
||||
bl ICFlashInvalidate
|
||||
sync
|
||||
isync
|
||||
mtlr addr
|
||||
blr
|
||||
frfree
|
||||
blr
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
inline void ReadApploader(DVDCommandBlock* dvdCmd, void* addr, u32 offset,
|
||||
u32 numBytes)
|
||||
{
|
||||
/* Not sure if this inline is correct - might need to call other inlines */
|
||||
while (Prepared == FALSE) { }
|
||||
DVDReadAbsAsyncForBS(dvdCmd, addr, numBytes, offset + 0x2440, NULL);
|
||||
|
||||
while (TRUE) {
|
||||
switch (dvdCmd->state) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
continue;
|
||||
case -1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
__OSDoHotReset(UNK_817FFFFC);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void Callback(s32 result, struct DVDCommandBlock* block)
|
||||
{
|
||||
Prepared = TRUE;
|
||||
}
|
||||
|
||||
void __OSReboot(u32 resetCode, u32 bootDol)
|
||||
{
|
||||
OSContext exceptionContext;
|
||||
DVDCommandBlock dvdCmd;
|
||||
DVDCommandBlock dvdCmd2;
|
||||
u32 numBytes;
|
||||
u32 offset;
|
||||
|
||||
OSDisableInterrupts();
|
||||
|
||||
UNK_817FFFFC = 0;
|
||||
UNK_817FFFF8 = 0;
|
||||
OS_REBOOT_BOOL = TRUE;
|
||||
BOOT_REGION_START = SaveStart;
|
||||
BOOT_REGION_END = SaveEnd;
|
||||
OSClearContext(&exceptionContext);
|
||||
OSSetCurrentContext(&exceptionContext);
|
||||
DVDInit();
|
||||
DVDSetAutoInvalidation(TRUE);
|
||||
|
||||
__DVDPrepareResetAsync(Callback);
|
||||
|
||||
if (!DVDCheckDisk()) {
|
||||
__OSDoHotReset(UNK_817FFFFC);
|
||||
}
|
||||
|
||||
__OSMaskInterrupts(0xffffffe0);
|
||||
__OSUnmaskInterrupts(0x400);
|
||||
|
||||
OSEnableInterrupts();
|
||||
|
||||
offset = 0;
|
||||
numBytes = 32;
|
||||
ReadApploader(&dvdCmd, (void*)&Header, offset, numBytes);
|
||||
|
||||
offset = Header.size + 0x20;
|
||||
numBytes = OSRoundUp32B(Header.rebootSize);
|
||||
ReadApploader(&dvdCmd2, OS_BOOTROM_ADDR, offset, numBytes);
|
||||
|
||||
ICInvalidateRange(OS_BOOTROM_ADDR, numBytes);
|
||||
Run(OS_BOOTROM_ADDR);
|
||||
}
|
||||
|
||||
void OSGetSaveRegion(void** start, void** end)
|
||||
{
|
||||
*start = SaveStart;
|
||||
*end = SaveEnd;
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/hw_regs.h>
|
||||
#include <macros.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
|
||||
// These macros are copied from OSThread.c. Or ARE they the same
|
||||
// macros? They dont seem to be in the SDK headers.
|
||||
#define ENQUEUE_INFO(info, queue) \
|
||||
do { \
|
||||
struct OSResetFunctionInfo* __prev = (queue)->tail; \
|
||||
if (__prev == 0) { \
|
||||
(queue)->head = (info); \
|
||||
} else { \
|
||||
__prev->next = (info); \
|
||||
} \
|
||||
(info)->prev = __prev; \
|
||||
(info)->next = 0; \
|
||||
(queue)->tail = (info); \
|
||||
} while (0);
|
||||
|
||||
#define DEQUEUE_INFO(info, queue) \
|
||||
do { \
|
||||
struct OSResetFunctionInfo* __next = (info)->next; \
|
||||
struct OSResetFunctionInfo* __prev = (info)->prev; \
|
||||
if (__next == 0) { \
|
||||
(queue)->tail = __prev; \
|
||||
} else { \
|
||||
__next->prev = __prev; \
|
||||
} \
|
||||
if (__prev == 0) { \
|
||||
(queue)->head = __next; \
|
||||
} else { \
|
||||
__prev->next = __next; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define ENQUEUE_INFO_PRIO(info, queue) \
|
||||
do { \
|
||||
struct OSResetFunctionInfo* __prev; \
|
||||
struct OSResetFunctionInfo* __next; \
|
||||
for (__next = (queue)->head; \
|
||||
__next && (__next->priority <= (info)->priority); \
|
||||
__next = __next->next) \
|
||||
; \
|
||||
\
|
||||
if (__next == 0) { \
|
||||
ENQUEUE_INFO(info, queue); \
|
||||
} else { \
|
||||
(info)->next = __next; \
|
||||
__prev = __next->prev; \
|
||||
__next->prev = (info); \
|
||||
(info)->prev = __prev; \
|
||||
if (__prev == 0) { \
|
||||
(queue)->head = (info); \
|
||||
} else { \
|
||||
__prev->next = (info); \
|
||||
} \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
static struct OSResetFunctionQueue ResetFunctionQueue;
|
||||
|
||||
static int CallResetFunctions(int final);
|
||||
static asm void Reset(unsigned long resetCode);
|
||||
|
||||
void OSRegisterResetFunction(struct OSResetFunctionInfo* info)
|
||||
{
|
||||
ENQUEUE_INFO_PRIO(info, &ResetFunctionQueue);
|
||||
}
|
||||
|
||||
void OSUnregisterResetFunction(struct OSResetFunctionInfo* info)
|
||||
{
|
||||
DEQUEUE_INFO(info, &ResetFunctionQueue);
|
||||
}
|
||||
|
||||
static int CallResetFunctions(int final)
|
||||
{
|
||||
struct OSResetFunctionInfo* info;
|
||||
int err = 0;
|
||||
|
||||
for (info = ResetFunctionQueue.head; info; info = info->next) {
|
||||
err |= !info->func(final);
|
||||
}
|
||||
err |= !__OSSyncSram();
|
||||
if (err) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static asm void Reset(unsigned long resetCode)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
b L_000001BC
|
||||
L_000001A0:
|
||||
mfspr r8, HID0
|
||||
ori r8, r8, 0x8
|
||||
mtspr HID0, r8
|
||||
isync
|
||||
sync
|
||||
nop
|
||||
b L_000001C0
|
||||
L_000001BC:
|
||||
b L_000001DC
|
||||
L_000001C0:
|
||||
mftb r5, 268
|
||||
L_000001C4:
|
||||
mftb r6, 268
|
||||
subf r7, r5, r6
|
||||
cmplwi r7, 0x1124
|
||||
blt L_000001C4
|
||||
nop
|
||||
b L_000001E0
|
||||
L_000001DC:
|
||||
b L_000001FC
|
||||
L_000001E0:
|
||||
lis r8, 0xcc00
|
||||
ori r8, r8, 0x3000
|
||||
li r4, 0x3
|
||||
stw r4, 0x24(r8)
|
||||
stw r3, 0x24(r8)
|
||||
nop
|
||||
b L_00000200
|
||||
L_000001FC:
|
||||
b L_00000208
|
||||
L_00000200:
|
||||
nop
|
||||
b L_00000200
|
||||
L_00000208:
|
||||
b L_000001A0
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
void __OSDoHotReset(s32 arg0)
|
||||
{
|
||||
OSDisableInterrupts();
|
||||
__VIRegs[1] = 0;
|
||||
ICFlashInvalidate();
|
||||
Reset(arg0 * 8);
|
||||
}
|
||||
|
||||
inline BOOL __OSCallResetFunctions(BOOL arg0)
|
||||
{
|
||||
OSResetFunctionInfo* iter;
|
||||
s32 retCode = 0;
|
||||
s32 temp;
|
||||
|
||||
for (iter = ResetFunctionQueue.head; iter != NULL;) {
|
||||
temp = !iter->func(arg0);
|
||||
iter = iter->next;
|
||||
retCode |= temp;
|
||||
}
|
||||
retCode |= !__OSSyncSram();
|
||||
if (retCode) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline 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);
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern u8 OS_REBOOT_BOOL AT_ADDRESS(0x800030E2);
|
||||
|
||||
void OSResetSystem(int reset, unsigned long resetCode, int forceMenu)
|
||||
{
|
||||
char trash[0x10]; // Either more inlines or more local vars, idk
|
||||
s32 padThing;
|
||||
|
||||
OSDisableScheduler();
|
||||
__OSStopAudioSystem();
|
||||
|
||||
if (reset == OS_RESET_SHUTDOWN)
|
||||
padThing = __PADDisableRecalibration(1);
|
||||
|
||||
do {
|
||||
} while (CallResetFunctions(0) == 0);
|
||||
|
||||
if ((reset == OS_RESET_HOTRESET && (forceMenu != 0))) {
|
||||
__OSLockSram()->flags |= 0x40;
|
||||
__OSUnlockSram(1);
|
||||
do {
|
||||
} while (__OSSyncSram() == 0);
|
||||
}
|
||||
|
||||
OSDisableInterrupts();
|
||||
__OSCallResetFunctions(TRUE);
|
||||
|
||||
LCDisable();
|
||||
|
||||
if (reset == OS_RESET_HOTRESET) {
|
||||
OSDisableInterrupts();
|
||||
__VIRegs[1] = 0;
|
||||
ICFlashInvalidate();
|
||||
Reset(resetCode * 8);
|
||||
} else if (reset == OS_RESET_RESTART) {
|
||||
KillThreads();
|
||||
OSEnableScheduler();
|
||||
__OSReboot(resetCode, forceMenu);
|
||||
}
|
||||
|
||||
KillThreads();
|
||||
|
||||
// TODO: maybe use AT_ADDRESS vars or macros from other files here?
|
||||
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(&OS_REBOOT_BOOL, 0, 1);
|
||||
__PADDisableRecalibration(padThing);
|
||||
}
|
||||
|
||||
u32 OSGetResetCode(void)
|
||||
{
|
||||
if (OS_REBOOT_BOOL != 0)
|
||||
return 0x80000000;
|
||||
|
||||
return ((__PIRegs[9] & ~7) >> 3);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/os/OSResetSW.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
|
||||
u8 GameChoice AT_ADDRESS(OS_BASE_CACHED | 0x30E3);
|
||||
|
||||
static OSResetCallback ResetCallback;
|
||||
|
||||
static BOOL Down;
|
||||
|
||||
static BOOL LastState;
|
||||
|
||||
static OSTime HoldUp;
|
||||
static OSTime HoldDown;
|
||||
|
||||
void __OSResetSWInterruptHandler(__OSInterrupt exception,
|
||||
struct 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 = OSDisableInterrupts();
|
||||
BOOL state;
|
||||
OSTime now = __OSGetSystemTime();
|
||||
u32 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;
|
||||
}
|
||||
|
||||
BOOL OSGetResetSwitchState(void) { return OSGetResetButtonState(); }
|
||||
@@ -0,0 +1,48 @@
|
||||
#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); }
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include "../src/static/dolphin/os/__os.h"
|
||||
|
||||
void __OSSystemCallVectorStart();
|
||||
void __OSSystemCallVectorEnd();
|
||||
|
||||
static asm void SystemCallVector(void)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
entry __OSSystemCallVectorStart
|
||||
nofralloc
|
||||
mfspr r9, HID0
|
||||
ori r10, r9, 0x8
|
||||
mtspr HID0, r10
|
||||
isync
|
||||
sync
|
||||
mtspr HID0, r9
|
||||
rfi
|
||||
entry __OSSystemCallVectorEnd
|
||||
nop
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
void __OSInitSystemCall(void)
|
||||
{
|
||||
void* addr = (void*)OSPhysicalToCached(0xC00);
|
||||
|
||||
memcpy(addr, __OSSystemCallVectorStart,
|
||||
(u32)&__OSSystemCallVectorEnd - (u32)&__OSSystemCallVectorStart);
|
||||
DCFlushRangeNoSync(addr, 0x100);
|
||||
__sync();
|
||||
ICInvalidateRange(addr, 0x100);
|
||||
}
|
||||
@@ -0,0 +1,806 @@
|
||||
#include <dolphin.h>
|
||||
#include <dolphin/base/PPCArch.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <macros.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
|
||||
#define IsSuspended(suspend) (suspend > 0)
|
||||
|
||||
#define ENQUEUE_THREAD(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __prev = (queue)->tail; \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = (thread); \
|
||||
} else { \
|
||||
__prev->link.next = (thread); \
|
||||
} \
|
||||
(thread)->link.prev = __prev; \
|
||||
(thread)->link.next = 0; \
|
||||
(queue)->tail = (thread); \
|
||||
} while (0);
|
||||
|
||||
#define DEQUEUE_THREAD(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __next = (thread)->link.next; \
|
||||
OSThread* __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 ENQUEUE_THREAD_PRIO(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __prev; \
|
||||
OSThread* __next; \
|
||||
for (__next = (queue)->head; \
|
||||
__next && (__next->priority <= (thread)->priority); \
|
||||
__next = __next->link.next) \
|
||||
; \
|
||||
\
|
||||
if (__next == NULL) { \
|
||||
ENQUEUE_THREAD(thread, queue, 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 DEQUEUE_HEAD(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __next = thread->link.next; \
|
||||
if (__next == NULL) { \
|
||||
(queue)->tail = 0; \
|
||||
} else { \
|
||||
__next->link.prev = 0; \
|
||||
} \
|
||||
(queue)->head = __next; \
|
||||
} while (0);
|
||||
|
||||
// which header should these go in?
|
||||
extern unsigned char _stack_end[];
|
||||
extern char _stack_addr[];
|
||||
|
||||
// .bss
|
||||
static OSThreadQueue RunQueue[32];
|
||||
static OSThread IdleThread;
|
||||
static OSThread DefaultThread;
|
||||
static struct OSContext IdleContext;
|
||||
static volatile unsigned long RunQueueBits;
|
||||
static volatile int RunQueueHint;
|
||||
static long Reschedule;
|
||||
|
||||
#define ALIGN4(val) (((val) + 0x3) & ~0x3)
|
||||
#define ALIGN8(val) (((val) + 0x7) & ~0x7)
|
||||
|
||||
// functions
|
||||
static void OSInitMutexQueue(struct OSMutexQueue* queue);
|
||||
static void __OSSwitchThread(OSThread* nextThread);
|
||||
static int __OSIsThreadActive(OSThread* thread);
|
||||
static void SetRun(OSThread* thread);
|
||||
static void UnsetRun(OSThread* thread);
|
||||
static OSThread* SetEffectivePriority(OSThread* thread, long priority);
|
||||
static void UpdatePriority(OSThread* thread);
|
||||
static OSThread* SelectThread(int yield);
|
||||
|
||||
void __OSThreadInit()
|
||||
{
|
||||
OSThread* thread = &DefaultThread;
|
||||
int prio;
|
||||
|
||||
thread->state = 2;
|
||||
thread->attr = 1;
|
||||
thread->priority = thread->base = 0x10;
|
||||
thread->suspend = 0;
|
||||
thread->val = (void*)-1; // wut
|
||||
thread->mutex = 0;
|
||||
|
||||
OSInitThreadQueue(&thread->queueJoin);
|
||||
|
||||
thread->queueMutex.head = thread->queueMutex.tail
|
||||
= 0; // it got inlined? cant reproduce the inline...
|
||||
|
||||
ASSERTLINE(282, PPCMfmsr() & MSR_FP);
|
||||
|
||||
__gUnkThread1 = thread;
|
||||
OSClearContext(&thread->context);
|
||||
OSSetCurrentContext(&thread->context);
|
||||
thread->stackBase = (unsigned char*)&_stack_addr;
|
||||
thread->stackEnd = (unsigned long*)&_stack_end;
|
||||
*(u32*)thread->stackEnd = 0xDEADBABE;
|
||||
__gCurrentThread = thread;
|
||||
RunQueueBits = 0;
|
||||
RunQueueHint = 0;
|
||||
|
||||
for (prio = 0; prio <= 31; prio++) {
|
||||
OSInitThreadQueue(&RunQueue[prio]);
|
||||
}
|
||||
OSInitThreadQueue(&__OSActiveThreadQueue);
|
||||
|
||||
ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
|
||||
OSClearContext(&IdleContext);
|
||||
Reschedule = 0;
|
||||
}
|
||||
|
||||
void OSInitThreadQueue(OSThreadQueue* queue) { queue->head = queue->tail = 0; }
|
||||
|
||||
OSThread* OSGetCurrentThread() { return __gCurrentThread; }
|
||||
|
||||
static void __OSSwitchThread(OSThread* nextThread)
|
||||
{
|
||||
__gCurrentThread = nextThread;
|
||||
OSSetCurrentContext(&nextThread->context);
|
||||
OSLoadContext(&nextThread->context);
|
||||
}
|
||||
|
||||
int OSIsThreadTerminated(OSThread* thread)
|
||||
{
|
||||
return (thread->state == 8 || thread->state == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int __OSIsThreadActive(OSThread* thread)
|
||||
{
|
||||
OSThread* active;
|
||||
|
||||
if (thread->state == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (active = __OSActiveThreadQueue.head; active;
|
||||
active = active->linkActive.next) {
|
||||
if (thread == active) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 OSDisableScheduler(void)
|
||||
{
|
||||
register int enabled;
|
||||
long count;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
count = Reschedule;
|
||||
Reschedule = count + 1;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return count;
|
||||
}
|
||||
|
||||
s32 OSEnableScheduler(void)
|
||||
{
|
||||
register int enabled;
|
||||
long count;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
count = Reschedule;
|
||||
Reschedule = count - 1;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void SetRun(OSThread* thread)
|
||||
{
|
||||
ASSERTLINE(469, !IsSuspended(thread->suspend));
|
||||
ASSERTLINE(470, thread->state == OS_THREAD_STATE_READY);
|
||||
|
||||
ASSERTLINE(472, OS_PRIORITY_MIN <= thread->priority
|
||||
&& thread->priority <= OS_PRIORITY_MAX);
|
||||
|
||||
thread->queue = &RunQueue[thread->priority];
|
||||
|
||||
ENQUEUE_THREAD(thread, thread->queue, link);
|
||||
|
||||
RunQueueBits |= 1 << (0x1F - thread->priority);
|
||||
RunQueueHint = 1;
|
||||
}
|
||||
|
||||
static void UnsetRun(OSThread* thread)
|
||||
{
|
||||
OSThreadQueue* queue;
|
||||
|
||||
ASSERTLINE(0x1ED, thread->state == OS_THREAD_STATE_READY);
|
||||
|
||||
ASSERTLINE(0x1EF, OS_PRIORITY_MIN <= thread->priority
|
||||
&& thread->priority <= OS_PRIORITY_MAX);
|
||||
ASSERTLINE(0x1F0, thread->queue == &RunQueue[thread->priority]);
|
||||
|
||||
queue = thread->queue;
|
||||
|
||||
DEQUEUE_THREAD(thread, queue, link);
|
||||
|
||||
if (!queue->head) {
|
||||
RunQueueBits &= ~(1 << (0x1F - thread->priority));
|
||||
}
|
||||
thread->queue = NULL;
|
||||
}
|
||||
|
||||
long __OSGetEffectivePriority(OSThread* thread)
|
||||
{
|
||||
long priority = thread->base;
|
||||
struct OSMutex* mutex;
|
||||
|
||||
for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) {
|
||||
OSThread* blocked = mutex->queue.head;
|
||||
if (blocked && blocked->priority < priority) {
|
||||
priority = blocked->priority;
|
||||
}
|
||||
}
|
||||
return priority;
|
||||
}
|
||||
|
||||
static OSThread* SetEffectivePriority(OSThread* thread, long priority)
|
||||
{
|
||||
ASSERTLINE(547, !IsSuspended(thread->suspend));
|
||||
|
||||
switch (thread->state) {
|
||||
case 1:
|
||||
UnsetRun(thread);
|
||||
thread->priority = priority;
|
||||
SetRun(thread);
|
||||
break;
|
||||
case 4:
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->priority = priority;
|
||||
|
||||
ENQUEUE_THREAD_PRIO(thread, thread->queue, link);
|
||||
|
||||
if (thread->mutex) {
|
||||
ASSERTLINE(0x232, thread->mutex->thread);
|
||||
return thread->mutex->thread;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
RunQueueHint = 1;
|
||||
thread->priority = priority;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void UpdatePriority(OSThread* thread)
|
||||
{
|
||||
long priority;
|
||||
|
||||
while (1) {
|
||||
if (thread->suspend > 0) {
|
||||
break;
|
||||
}
|
||||
priority = __OSGetEffectivePriority(thread);
|
||||
if (thread->priority == priority) {
|
||||
break;
|
||||
}
|
||||
thread = SetEffectivePriority(thread, priority);
|
||||
if (thread == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __OSPromoteThread(OSThread* thread, long priority)
|
||||
{
|
||||
while (1) {
|
||||
if (thread->suspend > 0 || thread->priority <= priority) {
|
||||
break;
|
||||
}
|
||||
thread = SetEffectivePriority(thread, priority);
|
||||
if (thread == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static OSThread* SelectThread(int yield)
|
||||
{
|
||||
struct OSContext* currentContext;
|
||||
OSThread* currentThread;
|
||||
OSThread* nextThread;
|
||||
long priority;
|
||||
OSThreadQueue* queue;
|
||||
|
||||
if (Reschedule > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
currentContext = OSGetCurrentContext();
|
||||
currentThread = OSGetCurrentThread();
|
||||
|
||||
if (currentContext != ¤tThread->context) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (currentThread) {
|
||||
if (currentThread->state == 2) {
|
||||
if (yield == 0) {
|
||||
priority = __cntlzw(RunQueueBits);
|
||||
if (currentThread->priority <= priority)
|
||||
return NULL;
|
||||
}
|
||||
currentThread->state = 1;
|
||||
SetRun(currentThread);
|
||||
}
|
||||
if (!(currentThread->context.state & 2)
|
||||
&& (OSSaveContext(¤tThread->context) != 0)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
__gCurrentThread = 0;
|
||||
|
||||
if (RunQueueBits == 0) {
|
||||
OSSetCurrentContext(&IdleContext);
|
||||
do {
|
||||
OSEnableInterrupts();
|
||||
while (RunQueueBits == 0)
|
||||
;
|
||||
OSDisableInterrupts();
|
||||
} while (RunQueueBits == 0);
|
||||
OSClearContext(&IdleContext);
|
||||
}
|
||||
|
||||
RunQueueHint = 0;
|
||||
priority = __cntlzw(RunQueueBits);
|
||||
|
||||
ASSERTLINE(0x2C6,
|
||||
OS_PRIORITY_MIN <= priority && priority <= OS_PRIORITY_MAX);
|
||||
|
||||
queue = &RunQueue[priority];
|
||||
nextThread = queue->head;
|
||||
|
||||
DEQUEUE_HEAD(nextThread, queue, link);
|
||||
|
||||
ASSERTLINE(0x2C9, nextThread->priority == priority);
|
||||
|
||||
if (!queue->head) {
|
||||
RunQueueBits &= ~(1 << (0x1F - priority));
|
||||
}
|
||||
nextThread->queue = 0;
|
||||
nextThread->state = 2;
|
||||
__OSSwitchThread(nextThread);
|
||||
return nextThread;
|
||||
}
|
||||
|
||||
void __OSReschedule(void)
|
||||
{
|
||||
if (RunQueueHint != 0) {
|
||||
SelectThread(0);
|
||||
}
|
||||
}
|
||||
|
||||
void OSYieldThread(void)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
|
||||
SelectThread(1);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param,
|
||||
void* stack, unsigned long stackSize, long priority,
|
||||
unsigned short attr)
|
||||
{
|
||||
int enabled;
|
||||
unsigned long sp;
|
||||
|
||||
ASSERTMSGLINE(
|
||||
0x31C, ((priority >= 0) && (priority <= 0x1F)),
|
||||
"OSCreateThread(): priority out of range (0 <= priority <= 31).");
|
||||
|
||||
// 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();
|
||||
|
||||
ASSERTMSG1LINE(0x33B, __OSIsThreadActive(thread) == 0L,
|
||||
"OSCreateThread(): thread %p is still active.", thread);
|
||||
|
||||
ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OSExitThread(void* val)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(0x354, currentThread,
|
||||
"OSExitThread(): current thread does not exist.");
|
||||
ASSERTMSGLINE(0x356, currentThread->state == 2,
|
||||
"OSExitThread(): current thread is not running.");
|
||||
ASSERTMSGLINE(0x358, __OSIsThreadActive(currentThread) != 0,
|
||||
"OSExitThread(): current thread is not active.");
|
||||
|
||||
OSClearContext(¤tThread->context);
|
||||
if (currentThread->attr & 1) {
|
||||
DEQUEUE_THREAD(currentThread, &__OSActiveThreadQueue, 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)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(0x37E, __OSIsThreadActive(thread) != 0,
|
||||
"OSExitThread(): thread %p is not active.", thread);
|
||||
|
||||
switch (thread->state) {
|
||||
case 1:
|
||||
if (thread->suspend <= 0) {
|
||||
UnsetRun(thread);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
RunQueueHint = 1;
|
||||
break;
|
||||
case 4:
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->queue = 0;
|
||||
if ((thread->suspend <= 0) && (thread->mutex)) {
|
||||
ASSERTLINE(0x391, thread->mutex->thread);
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OSRestoreInterrupts(enabled);
|
||||
return;
|
||||
}
|
||||
OSClearContext(&thread->context);
|
||||
if (thread->attr & 1) {
|
||||
DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
thread->state = 0;
|
||||
} else {
|
||||
thread->state = 8;
|
||||
}
|
||||
__OSUnlockAllMutex(thread);
|
||||
OSWakeupThread(&thread->queueJoin);
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int OSJoinThread(OSThread* thread, void** val)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(0x3CA, __OSIsThreadActive(thread) != 0,
|
||||
"OSJoinThread(): thread %p is not active.", thread);
|
||||
|
||||
if (!(thread->attr & 1) && (thread->state != 8)
|
||||
&& (thread->queueJoin.head == NULL)) {
|
||||
OSSleepThread(&thread->queueJoin);
|
||||
if (__OSIsThreadActive(thread) == 0) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (thread->state == 8) {
|
||||
if (val) {
|
||||
*val = thread->val;
|
||||
}
|
||||
DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
thread->state = 0;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OSDetachThread(OSThread* thread)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(0x3FC, __OSIsThreadActive(thread) != 0,
|
||||
"OSDetachThread(): thread %p is not active.", thread);
|
||||
|
||||
thread->attr |= 1;
|
||||
if (thread->state == 8) {
|
||||
DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
thread->state = 0;
|
||||
}
|
||||
OSWakeupThread(&thread->queueJoin);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
long OSResumeThread(OSThread* thread)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
long suspendCount;
|
||||
|
||||
ASSERTMSG1LINE(0x419, __OSIsThreadActive(thread) != 0,
|
||||
"OSResumeThread(): thread %p is not active.", thread);
|
||||
ASSERTMSG1LINE(0x41B, thread->state != 8,
|
||||
"OSResumeThread(): thread %p is terminated.", thread);
|
||||
|
||||
suspendCount = thread->suspend--;
|
||||
if (thread->suspend < 0) {
|
||||
thread->suspend = 0;
|
||||
} else if (thread->suspend == 0) {
|
||||
switch (thread->state) {
|
||||
case 1:
|
||||
thread->priority = __OSGetEffectivePriority(thread);
|
||||
SetRun(thread);
|
||||
break;
|
||||
case 4:
|
||||
ASSERTLINE(0x42A, thread->queue);
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->priority = __OSGetEffectivePriority(thread);
|
||||
ENQUEUE_THREAD_PRIO(thread, thread->queue, link);
|
||||
if (thread->mutex) {
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
}
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return suspendCount;
|
||||
}
|
||||
|
||||
long OSSuspendThread(OSThread* thread)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
long suspendCount;
|
||||
|
||||
ASSERTMSG1LINE(0x44C, __OSIsThreadActive(thread) != 0,
|
||||
"OSSuspendThread(): thread %p is not active.", thread);
|
||||
ASSERTMSG1LINE(0x44E, thread->state != 8,
|
||||
"OSSuspendThread(): thread %p is terminated.", thread);
|
||||
|
||||
suspendCount = thread->suspend++;
|
||||
if (suspendCount == 0) {
|
||||
switch (thread->state) {
|
||||
case 2:
|
||||
RunQueueHint = 1;
|
||||
thread->state = 1;
|
||||
break;
|
||||
case 1:
|
||||
UnsetRun(thread);
|
||||
break;
|
||||
case 4:
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->priority = 0x20;
|
||||
ENQUEUE_THREAD(thread, thread->queue, link);
|
||||
if (thread->mutex) {
|
||||
ASSERTLINE(0x463, thread->mutex->thread);
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
break;
|
||||
}
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return suspendCount;
|
||||
}
|
||||
|
||||
void OSSleepThread(OSThreadQueue* queue)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(0x484, currentThread,
|
||||
"OSSleepThread(): current thread does not exist.");
|
||||
ASSERTMSG1LINE(0x486, __OSIsThreadActive(currentThread) != 0,
|
||||
"OSSleepThread(): current thread %p is not active.",
|
||||
currentThread);
|
||||
ASSERTMSG1LINE(0x488, currentThread->state == 2,
|
||||
"OSSleepThread(): current thread %p is not running.",
|
||||
currentThread);
|
||||
ASSERTMSG1LINE(0x48A, currentThread->suspend <= 0,
|
||||
"OSSleepThread(): current thread %p is suspended.",
|
||||
currentThread);
|
||||
|
||||
currentThread->state = 4;
|
||||
currentThread->queue = queue;
|
||||
ENQUEUE_THREAD_PRIO(currentThread, queue, link);
|
||||
RunQueueHint = 1;
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSWakeupThread(OSThreadQueue* queue)
|
||||
{
|
||||
int enabled = OSDisableInterrupts();
|
||||
|
||||
while (queue->head) {
|
||||
OSThread* thread = queue->head;
|
||||
|
||||
DEQUEUE_HEAD(thread, queue, link);
|
||||
|
||||
ASSERTLINE(0x4A7, __OSIsThreadActive(thread));
|
||||
ASSERTLINE(0x4A8, thread->state != OS_THREAD_STATE_MORIBUND);
|
||||
ASSERTLINE(0x4A9, thread->queue == queue);
|
||||
thread->state = 1;
|
||||
if (thread->suspend <= 0) {
|
||||
SetRun(thread);
|
||||
}
|
||||
}
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int OSSetThreadPriority(struct OSThread * thread, long priority) {
|
||||
int enabled;
|
||||
|
||||
ASSERTMSGLINE(0x4C3, (priority >= 0) && (priority <= 0x1F), "OSSetThreadPriority(): priority out of range (0 <= priority <= 31).");
|
||||
|
||||
if ((priority < 0) || (priority > 0x1F)) {
|
||||
return 0;
|
||||
}
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(0x4CA, __OSIsThreadActive(thread) != 0, "OSSetThreadPriority(): thread %p is not active.", thread);
|
||||
ASSERTMSG1LINE(0x4CC, thread->state != 8, "OSSetThreadPriority(): thread %p is terminated.", thread);
|
||||
|
||||
if (thread->base != priority) {
|
||||
thread->base = priority;
|
||||
UpdatePriority(thread);
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
long OSGetThreadPriority(OSThread* thread) { return thread->base; }
|
||||
|
||||
|
||||
static int CheckThreadQueue(struct OSThreadQueue * queue) {
|
||||
struct OSThread * thread;
|
||||
|
||||
if ((queue->head != NULL) && (queue->head->link.prev != NULL)) {
|
||||
return 0;
|
||||
}
|
||||
if ((queue->tail != NULL) && (queue->tail->link.next != NULL)) {
|
||||
return 0;
|
||||
}
|
||||
thread = queue->head;
|
||||
while(thread) {
|
||||
if ((thread->link.next != NULL) && (thread != thread->link.next->link.prev)) {
|
||||
return 0;
|
||||
}
|
||||
if ((thread->link.prev != NULL) && (thread != thread->link.prev->link.next)) {
|
||||
return 0;
|
||||
}
|
||||
thread = thread->link.next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int IsMember(struct OSThreadQueue * queue, struct OSThread * thread) {
|
||||
struct OSThread * member = queue->head;
|
||||
|
||||
while(member) {
|
||||
if (thread == member) {
|
||||
return 1;
|
||||
}
|
||||
member = member->link.next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ASSERTREPORT(line, cond) \
|
||||
if (!(cond)) { \
|
||||
OSReport("OSCheckActiveThreads: Failed " #cond " in %d\n", line); \
|
||||
OSPanic(__FILE__, line, ""); \
|
||||
}
|
||||
|
||||
long OSCheckActiveThreads() {
|
||||
struct OSThread * thread;
|
||||
long prio;
|
||||
long cThread;
|
||||
int enabled;
|
||||
|
||||
cThread = 0;
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
for(prio = 0; prio <= 0x1F; prio++) {
|
||||
if (RunQueueBits & (1 << (0x1F - prio))) {
|
||||
ASSERTREPORT(0x566, RunQueue[prio].head != NULL && RunQueue[prio].tail != NULL);
|
||||
} else {
|
||||
ASSERTREPORT(0x56B, RunQueue[prio].head == NULL && RunQueue[prio].tail == NULL);
|
||||
}
|
||||
ASSERTREPORT(0x56D, CheckThreadQueue(&RunQueue[prio]));
|
||||
}
|
||||
|
||||
ASSERTREPORT(0x572, __OSActiveThreadQueue.head == NULL || __OSActiveThreadQueue.head->linkActive.prev == NULL);
|
||||
ASSERTREPORT(0x574, __OSActiveThreadQueue.tail == NULL || __OSActiveThreadQueue.tail->linkActive.next == NULL);
|
||||
|
||||
thread = __OSActiveThreadQueue.head;
|
||||
while(thread) {
|
||||
cThread++;
|
||||
ASSERTREPORT(0x57C, thread->linkActive.next == NULL || thread == thread->linkActive.next->linkActive.prev);
|
||||
ASSERTREPORT(0x57E, thread->linkActive.prev == NULL || thread == thread->linkActive.prev->linkActive.next);
|
||||
ASSERTREPORT(0x581, *(thread->stackEnd) == OS_THREAD_STACK_MAGIC);
|
||||
ASSERTREPORT(0x584, OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX+1);
|
||||
ASSERTREPORT(0x585, 0 <= thread->suspend);
|
||||
ASSERTREPORT(0x586, CheckThreadQueue(&thread->queueJoin));
|
||||
|
||||
switch(thread->state) {
|
||||
case 1:
|
||||
if (thread->suspend <= 0) {
|
||||
ASSERTREPORT(0x58C, thread->queue == &RunQueue[thread->priority]);
|
||||
ASSERTREPORT(0x58D, IsMember(&RunQueue[thread->priority], thread));
|
||||
ASSERTREPORT(0x58E, thread->priority == __OSGetEffectivePriority(thread));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
ASSERTREPORT(0x592, !IsSuspended(thread->suspend));
|
||||
ASSERTREPORT(0x593, thread->queue == NULL);
|
||||
ASSERTREPORT(0x594, thread->priority == __OSGetEffectivePriority(thread));
|
||||
break;
|
||||
case 4:
|
||||
ASSERTREPORT(0x597, thread->queue != NULL);
|
||||
ASSERTREPORT(0x598, CheckThreadQueue(thread->queue));
|
||||
ASSERTREPORT(0x599, IsMember(thread->queue, thread));
|
||||
if (thread->suspend <= 0) {
|
||||
ASSERTREPORT(0x59C, thread->priority == __OSGetEffectivePriority(thread));
|
||||
} else {
|
||||
ASSERTREPORT(0x5A0, thread->priority == 32);
|
||||
}
|
||||
ASSERTREPORT(0x5A2, !__OSCheckDeadLock(thread));
|
||||
break;
|
||||
case 8:
|
||||
ASSERTREPORT(0x5A6, thread->queueMutex.head == NULL && thread->queueMutex.tail == NULL);
|
||||
break;
|
||||
default:
|
||||
OSReport("OSCheckActiveThreads: Failed. unkown thread state (%d) of thread %p\n", thread->state, thread);
|
||||
OSPanic("OSThread.c", 0x5AC, "");
|
||||
}
|
||||
ASSERTREPORT(0x5B1, __OSCheckMutexes(thread));
|
||||
thread = thread->linkActive.next;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return cThread;
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
#include <dolphin/exi.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <macros.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
|
||||
// End of each month in standard year
|
||||
static int YearDays[MONTH_MAX]
|
||||
= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||
// End of each month in leap year
|
||||
static int LeapYearDays[MONTH_MAX]
|
||||
= { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
|
||||
|
||||
asm long long OSGetTime(void)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
jump:
|
||||
nofralloc
|
||||
|
||||
mftbu r3
|
||||
mftb r4
|
||||
|
||||
// Check for possible carry from TBL to TBU
|
||||
mftbu r5
|
||||
cmpw r3, r5
|
||||
bne jump
|
||||
|
||||
blr
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
asm unsigned long OSGetTick(void)
|
||||
{
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
|
||||
mftb r3
|
||||
blr
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
long long __OSGetSystemTime()
|
||||
{
|
||||
int enabled;
|
||||
long long* timeAdjustAddr;
|
||||
long long result;
|
||||
|
||||
timeAdjustAddr = (long long*)0x800030D8;
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
result = OSGetTime() + *timeAdjustAddr;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int IsLeapYear(int year)
|
||||
{
|
||||
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
static int GetYearDays(int year, int mon) {
|
||||
int* md = (IsLeapYear(year)) ? LeapYearDays : YearDays;
|
||||
|
||||
return md[mon];
|
||||
}
|
||||
|
||||
static int GetLeapDays(int year)
|
||||
{
|
||||
ASSERTLINE(260, 0 <= year);
|
||||
|
||||
if (year < 1) {
|
||||
return 0;
|
||||
}
|
||||
return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400;
|
||||
}
|
||||
|
||||
static void GetDates(int days, OSCalendarTime* td)
|
||||
{
|
||||
int year;
|
||||
int n;
|
||||
int month;
|
||||
int* md;
|
||||
|
||||
ASSERTLINE(285, 0 <= days);
|
||||
|
||||
td->wday = (days + 6) % WEEK_DAY_MAX;
|
||||
|
||||
for (year = days / YEAR_DAY_MAX;
|
||||
days < (n = year * YEAR_DAY_MAX + GetLeapDays(year)); year--) {
|
||||
;
|
||||
}
|
||||
|
||||
days -= n;
|
||||
td->year = year;
|
||||
td->yday = days;
|
||||
|
||||
md = IsLeapYear(year) ? LeapYearDays : YearDays;
|
||||
for (month = MONTH_MAX; days < md[--month];) {
|
||||
;
|
||||
}
|
||||
td->mon = month;
|
||||
td->mday = days - md[month] + 1;
|
||||
}
|
||||
|
||||
void OSTicksToCalendarTime(long long ticks, OSCalendarTime* td)
|
||||
{
|
||||
int days;
|
||||
int secs;
|
||||
long long d;
|
||||
|
||||
d = ticks % OSSecondsToTicks(1);
|
||||
if (d < 0) {
|
||||
d += OSSecondsToTicks(1);
|
||||
ASSERTLINE(330, 0 <= d);
|
||||
}
|
||||
|
||||
td->usec = OSTicksToMicroseconds(d) % USEC_MAX;
|
||||
td->msec = OSTicksToMilliseconds(d) % MSEC_MAX;
|
||||
|
||||
ASSERTLINE(334, 0 <= td->usec);
|
||||
ASSERTLINE(335, 0 <= td->msec);
|
||||
|
||||
ticks -= d;
|
||||
|
||||
ASSERTLINE(338, ticks % OSSecondsToTicks(1) == 0);
|
||||
ASSERTLINE(342, 0 <= OSTicksToSeconds(ticks) / 86400 + BIAS
|
||||
&& OSTicksToSeconds(ticks) / 86400 + BIAS <= INT_MAX);
|
||||
|
||||
days = (OSTicksToSeconds(ticks) / SECS_IN_DAY) + BIAS;
|
||||
secs = OSTicksToSeconds(ticks) % SECS_IN_DAY;
|
||||
if (secs < 0) {
|
||||
days -= 1;
|
||||
secs += SECS_IN_DAY;
|
||||
ASSERTLINE(349, 0 <= secs);
|
||||
}
|
||||
|
||||
GetDates(days, td);
|
||||
td->hour = secs / 60 / 60;
|
||||
td->min = secs / 60 % 60;
|
||||
td->sec = secs % 60;
|
||||
}
|
||||
|
||||
OSTime OSCalendarTimeToTicks(OSCalendarTime* td) {
|
||||
OSTime secs;
|
||||
int ov_mon;
|
||||
int mon;
|
||||
int year;
|
||||
|
||||
ov_mon = td->mon / MONTH_MAX;
|
||||
mon = td->mon - (ov_mon * MONTH_MAX);
|
||||
|
||||
if (mon < 0) {
|
||||
mon += MONTH_MAX;
|
||||
ov_mon--;
|
||||
}
|
||||
|
||||
ASSERTLINE(412, (ov_mon <= 0 && 0 <= td->year + ov_mon) || (0 < ov_mon && td->year <= INT_MAX - ov_mon));
|
||||
|
||||
year = td->year + ov_mon;
|
||||
|
||||
secs = (OSTime)SECS_IN_YEAR * year +
|
||||
(OSTime)SECS_IN_DAY * (GetLeapDays(year) + GetYearDays(year, mon) + td->mday - 1) +
|
||||
(OSTime)SECS_IN_HOUR * td->hour +
|
||||
(OSTime)SECS_IN_MIN * td->min +
|
||||
td->sec -
|
||||
(OSTime)0xEB1E1BF80ULL;
|
||||
|
||||
return OSSecondsToTicks(secs) + OSMillisecondsToTicks((OSTime)td->msec) +
|
||||
OSMicrosecondsToTicks((OSTime)td->usec);
|
||||
}
|
||||
@@ -4,11 +4,14 @@
|
||||
#include <dolphin/os.h>
|
||||
|
||||
// OS.c
|
||||
extern char * __OSExceptionNames[15]; // D ONLY
|
||||
extern char* __OSExceptionNames[15]; // D ONLY
|
||||
extern OSTime __OSStartTime;
|
||||
|
||||
unsigned long __OSIsDebuggerPresent(void);
|
||||
void __OSPSInit(void);
|
||||
unsigned long __OSGetDIConfig(void);
|
||||
|
||||
extern void* BOOT_REGION_START AT_ADDRESS(0x812FDFF0);
|
||||
extern void* BOOT_REGION_END AT_ADDRESS(0x812FDFEC);
|
||||
|
||||
// OSAlloc.c
|
||||
extern volatile int __OSCurrHeap;
|
||||
@@ -23,18 +26,24 @@ void __OSCacheInit(void);
|
||||
// OSContext.c
|
||||
void __OSContextInit(void);
|
||||
|
||||
// OSMemory.c
|
||||
void __OSInitMemoryProtection(void);
|
||||
|
||||
// OSError.c
|
||||
void __OSUnhandledException(unsigned char exception, struct OSContext * context, unsigned long dsisr, unsigned long dar);
|
||||
void __OSUnhandledException(unsigned char exception, struct OSContext* context,
|
||||
unsigned long dsisr, unsigned long dar);
|
||||
|
||||
// OSInterrupt.c
|
||||
extern void __RAS_OSDisableInterrupts_begin(void);
|
||||
extern void __RAS_OSDisableInterrupts_end(void);
|
||||
|
||||
extern unsigned long long __OSSpuriousInterrupts; // D ONLY
|
||||
extern char * __OSInterruptNames[33]; // D ONLY
|
||||
extern char * __OSPIErrors[8]; // D ONLY
|
||||
extern char* __OSInterruptNames[33]; // D ONLY
|
||||
extern char* __OSPIErrors[8]; // D ONLY
|
||||
extern OSErrorHandlerEx __OSErrorTable[16];
|
||||
|
||||
__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler);
|
||||
__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt,
|
||||
__OSInterruptHandler handler);
|
||||
__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt);
|
||||
void __OSInterruptInit(void);
|
||||
OSInterruptMask __OSMaskInterrupts(OSInterruptMask global);
|
||||
@@ -43,25 +52,33 @@ void __OSDispatchInterrupt(__OSException exception, OSContext* context);
|
||||
void __OSModuleInit(void);
|
||||
|
||||
// OSMutex.c
|
||||
void __OSUnlockAllMutex(struct OSThread *thread);
|
||||
int __OSCheckDeadLock(struct OSThread *thread);
|
||||
int __OSCheckMutexes(struct OSThread *thread);
|
||||
void __OSUnlockAllMutex(struct OSThread* thread);
|
||||
int __OSCheckDeadLock(struct OSThread* thread);
|
||||
int __OSCheckMutexes(struct OSThread* thread);
|
||||
|
||||
// OSResetSW.c
|
||||
void __OSResetSWInterruptHandler(short exception, struct OSContext *context);
|
||||
void __OSResetSWInterruptHandler(__OSInterrupt exception,
|
||||
struct OSContext* context);
|
||||
|
||||
// OSReset.c
|
||||
void __OSDoHotReset(s32);
|
||||
|
||||
// OSReboot.c
|
||||
void __OSReboot(u32, u32);
|
||||
|
||||
// OSRtc.c
|
||||
int __OSGetRTC(unsigned long * rtc);
|
||||
int __OSGetRTC(unsigned long* rtc);
|
||||
int __OSSetRTC(unsigned long rtc);
|
||||
void __OSInitSram();
|
||||
struct OSSram * __OSLockSram(void);
|
||||
struct OSSramEx * __OSLockSramEx(void);
|
||||
struct OSSram* __OSLockSram(void);
|
||||
struct OSSramEx* __OSLockSramEx(void);
|
||||
int __OSUnlockSram(int commit);
|
||||
int __OSUnlockSramEx(int commit);
|
||||
int __OSSyncSram(void);
|
||||
int __OSCheckSram(void);
|
||||
int __OSReadROM(void * buffer, long length, long offset);
|
||||
int __OSReadROMAsync(void * buffer, long length, long offset, void (* callback)());
|
||||
int __OSReadROM(void* buffer, long length, long offset);
|
||||
int __OSReadROMAsync(void* buffer, long length, long offset,
|
||||
void (*callback)());
|
||||
unsigned char __OSGetBootMode(void);
|
||||
void __OSSetBootMode(unsigned char ntd);
|
||||
|
||||
@@ -73,8 +90,8 @@ void __OSInitSystemCall(void);
|
||||
|
||||
// OSThread.c
|
||||
void __OSThreadInit(void);
|
||||
long __OSGetEffectivePriority(struct OSThread * thread);
|
||||
void __OSPromoteThread(struct OSThread * thread, long priority);
|
||||
long __OSGetEffectivePriority(struct OSThread* thread);
|
||||
void __OSPromoteThread(struct OSThread* thread, long priority);
|
||||
void __OSReschedule(void);
|
||||
|
||||
// OSTime.c
|
||||
@@ -82,9 +99,12 @@ void __OSSetTime(long long time);
|
||||
long long __OSGetSystemTime();
|
||||
void __OSSetTick(register unsigned long newTicks);
|
||||
|
||||
extern u32 __OSGetDIConfig(void);
|
||||
|
||||
// ppc_eabi_init.c
|
||||
__declspec(section ".init") asm void __init_hardware(void);
|
||||
__declspec(section ".init") asm void __flush_cache(void *address, unsigned int size);
|
||||
__declspec(section ".init") asm void __flush_cache(void* address,
|
||||
unsigned int size);
|
||||
void __init_user(void);
|
||||
void __init_cpp(void);
|
||||
void __fini_cpp(void);
|
||||
@@ -94,17 +114,10 @@ void _ExitProcess(void);
|
||||
void __start(void);
|
||||
|
||||
__declspec(section ".init") extern void __start(void);
|
||||
__declspec(section ".init") void __copy_rom_section(void* dst, const void* src, unsigned long size);
|
||||
__declspec(section ".init") void __init_bss_section(void* dst, unsigned long size);
|
||||
__declspec(section ".init") extern void __init_registers(void);
|
||||
__declspec(section ".init") extern void __init_data(void);
|
||||
|
||||
// time.dolphin.c
|
||||
long long __get_clock(void);
|
||||
unsigned long __get_time(void);
|
||||
int __to_gm_time(void);
|
||||
|
||||
// EXIUart.c
|
||||
void __OSEnableBarnacle(s32 chan, u32 dev);
|
||||
|
||||
#endif // _DOLPHIN_OS_INTERNAL_H_
|
||||
|
||||
@@ -342,7 +342,7 @@ extern void DSPInit2 (DSPTaskInfo2* task){
|
||||
u16 tmp;
|
||||
|
||||
enable = OSDisableInterrupts();
|
||||
__OSUnmaskInterrupts(OS_INTRMASK_DSP_DSP);
|
||||
__OSUnmaskInterrupts(OS_INTERRUPTMASK_DSP_DSP);
|
||||
|
||||
tmp = __DSPRegs[DSP_CONTROL_STATUS];
|
||||
tmp = (tmp & ~0xA8)| 0x800;
|
||||
|
||||
Reference in New Issue
Block a user