mirror of
https://github.com/zeldaret/tww.git
synced 2024-11-23 13:29:53 +00:00
Copy dolphin/os progress from TP decomp
This commit is contained in:
parent
fcbfe1e299
commit
09e3562a32
14
configure.py
14
configure.py
@ -965,22 +965,22 @@ config.libs = [
|
||||
Object(NonMatching, "dolphin/os/OS.c"),
|
||||
Object(NonMatching, "dolphin/os/OSAlarm.c"),
|
||||
Object(NonMatching, "dolphin/os/OSAlloc.c"),
|
||||
Object(NonMatching, "dolphin/os/OSArena.c"),
|
||||
Object(NonMatching, "dolphin/os/OSAudioSystem.c"),
|
||||
Object(Matching, "dolphin/os/OSArena.c"),
|
||||
Object(Matching, "dolphin/os/OSAudioSystem.c"),
|
||||
Object(NonMatching, "dolphin/os/OSCache.c"),
|
||||
Object(NonMatching, "dolphin/os/OSContext.c"),
|
||||
Object(NonMatching, "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/OSMessage.c"),
|
||||
Object(Matching, "dolphin/os/OSInterrupt.c"),
|
||||
Object(Matching, "dolphin/os/OSLink.c"),
|
||||
Object(Matching, "dolphin/os/OSMessage.c"),
|
||||
Object(NonMatching, "dolphin/os/OSMemory.c"),
|
||||
Object(NonMatching, "dolphin/os/OSMutex.c"),
|
||||
Object(Matching, "dolphin/os/OSMutex.c"),
|
||||
Object(NonMatching, "dolphin/os/OSReboot.c"),
|
||||
Object(NonMatching, "dolphin/os/OSReset.c"),
|
||||
Object(NonMatching, "dolphin/os/OSResetSW.c"),
|
||||
Object(NonMatching, "dolphin/os/OSRtc.c"),
|
||||
Object(NonMatching, "dolphin/os/OSSync.c"),
|
||||
Object(Matching, "dolphin/os/OSSync.c"),
|
||||
Object(NonMatching, "dolphin/os/OSThread.c"),
|
||||
Object(NonMatching, "dolphin/os/OSTime.c"),
|
||||
Object(NonMatching, "dolphin/os/__ppc_eabi_init.cpp"),
|
||||
|
@ -1,9 +1,8 @@
|
||||
#ifndef DYNAMICLINK_H
|
||||
#define DYNAMICLINK_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
typedef struct OSModuleInfo OSModuleInfo;
|
||||
class JKRArchive;
|
||||
class JKRFileCache;
|
||||
class mDoDvdThd_callback_c;
|
||||
@ -57,7 +56,7 @@ struct DynamicModuleControl : DynamicModuleControlBase {
|
||||
static bool initialize();
|
||||
static bool callback(void*);
|
||||
|
||||
/* 0x10 */ OSModuleInfo* mModule;
|
||||
/* 0x10 */ OSModuleHeader* mModule;
|
||||
/* 0x14 */ void* mBss;
|
||||
/* 0x18 */ u32 unk_24;
|
||||
/* 0x1c */ const char* mName;
|
||||
|
@ -20,6 +20,29 @@ extern "C" {
|
||||
#define DSP_TASK_STATE_YIELD 2
|
||||
#define DSP_TASK_STATE_DONE 3
|
||||
|
||||
#define DSP_MAILBOX_IN_HI (0)
|
||||
#define DSP_MAILBOX_IN_LO (1)
|
||||
#define DSP_MAILBOX_OUT_HI (2)
|
||||
#define DSP_MAILBOX_OUT_LO (3)
|
||||
#define DSP_CONTROL_STATUS (5)
|
||||
|
||||
#define DSP_ARAM_SIZE (9)
|
||||
#define DSP_ARAM_MODE (11)
|
||||
#define DSP_ARAM_REFRESH (13)
|
||||
#define DSP_ARAM_DMA_MM_HI (16) // Main mem address
|
||||
#define DSP_ARAM_DMA_MM_LO (17)
|
||||
#define DSP_ARAM_DMA_ARAM_HI (18) // ARAM address
|
||||
#define DSP_ARAM_DMA_ARAM_LO (19)
|
||||
#define DSP_ARAM_DMA_SIZE_HI (20) // DMA buffer size
|
||||
#define DSP_ARAM_DMA_SIZE_LO (21)
|
||||
|
||||
#define DSP_DMA_START_HI (24) // DMA start address
|
||||
#define DSP_DMA_START_LO (25)
|
||||
#define DSP_DMA_CONTROL_LEN (27)
|
||||
#define DSP_DMA_BYTES_LEFT (29)
|
||||
|
||||
#define DSP_DMA_START_FLAG (0x8000) // set to start DSP
|
||||
|
||||
typedef void (*DSPCallback)(void* task);
|
||||
|
||||
typedef struct STRUCT_DSP_TASK {
|
||||
|
@ -1,5 +1,8 @@
|
||||
#ifndef DVDFS_H
|
||||
#define DVDFS_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
|
||||
extern u32 __DVDLongFileNameFlag;
|
||||
|
||||
#endif /* DVDFS_H */
|
||||
|
109
include/dolphin/exi/EXIBios.h
Normal file
109
include/dolphin/exi/EXIBios.h
Normal file
@ -0,0 +1,109 @@
|
||||
#ifndef EXIBIOS_H
|
||||
#define EXIBIOS_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct OSContext OSContext;
|
||||
|
||||
vu32 __EXIRegs[16] : 0xCC006800;
|
||||
|
||||
#define EXI_MEMORY_CARD_59 0x00000004
|
||||
#define EXI_MEMORY_CARD_123 0x00000008
|
||||
#define EXI_MEMORY_CARD_251 0x00000010
|
||||
#define EXI_MEMORY_CARD_507 0x00000020
|
||||
|
||||
#define EXI_MEMORY_CARD_1019 0x00000040
|
||||
#define EXI_MEMORY_CARD_2043 0x00000080
|
||||
|
||||
#define EXI_MEMORY_CARD_1019A 0x00000140
|
||||
#define EXI_MEMORY_CARD_1019B 0x00000240
|
||||
#define EXI_MEMORY_CARD_1019C 0x00000340
|
||||
#define EXI_MEMORY_CARD_1019D 0x00000440
|
||||
#define EXI_MEMORY_CARD_1019E 0x00000540
|
||||
#define EXI_MEMORY_CARD_1019F 0x00000640
|
||||
#define EXI_MEMORY_CARD_1019G 0x00000740
|
||||
|
||||
#define EXI_MEMORY_CARD_2043A 0x00000180
|
||||
#define EXI_MEMORY_CARD_2043B 0x00000280
|
||||
#define EXI_MEMORY_CARD_2043C 0x00000380
|
||||
#define EXI_MEMORY_CARD_2043D 0x00000480
|
||||
#define EXI_MEMORY_CARD_2043E 0x00000580
|
||||
#define EXI_MEMORY_CARD_2043F 0x00000680
|
||||
#define EXI_MEMORY_CARD_2043G 0x00000780
|
||||
|
||||
#define EXI_USB_ADAPTER 0x01010000
|
||||
#define EXI_NPDP_GDEV 0x01020000
|
||||
|
||||
#define EXI_MODEM 0x02020000
|
||||
#define EXI_ETHER 0x04020200
|
||||
#define EXI_ETHER_VIEWER 0x04220001
|
||||
#define EXI_STREAM_HANGER 0x04130000
|
||||
|
||||
#define EXI_MARLIN 0x03010000
|
||||
|
||||
#define EXI_IS_VIEWER 0x05070000
|
||||
|
||||
#define EXI_FREQ_1M 0
|
||||
#define EXI_FREQ_2M 1
|
||||
#define EXI_FREQ_4M 2
|
||||
#define EXI_FREQ_8M 3
|
||||
#define EXI_FREQ_16M 4
|
||||
#define EXI_FREQ_32M 5
|
||||
|
||||
#define EXI_READ 0
|
||||
#define EXI_WRITE 1
|
||||
|
||||
#define EXI_STATE_IDLE 0x00
|
||||
#define EXI_STATE_DMA 0x01
|
||||
#define EXI_STATE_IMM 0x02
|
||||
#define EXI_STATE_BUSY (EXI_STATE_DMA | EXI_STATE_IMM)
|
||||
#define EXI_STATE_SELECTED 0x04
|
||||
#define EXI_STATE_ATTACHED 0x08
|
||||
#define EXI_STATE_LOCKED 0x10
|
||||
|
||||
typedef void (*EXICallback)(s32 chan, OSContext* context);
|
||||
|
||||
typedef struct EXIControl {
|
||||
EXICallback exiCallback;
|
||||
EXICallback tcCallback;
|
||||
EXICallback extCallback;
|
||||
vu32 state;
|
||||
int immLen;
|
||||
u8* immBuf;
|
||||
u32 dev;
|
||||
u32 id;
|
||||
s32 idTime;
|
||||
int items;
|
||||
struct {
|
||||
u32 dev;
|
||||
EXICallback callback;
|
||||
} queue[3];
|
||||
} EXIControl;
|
||||
|
||||
s32 EXIImm(s32 chan, void* buf, s32 len, u32 type, EXICallback callback);
|
||||
s32 EXIImmEx(s32 chan, void* buf, s32 len, u32 mode);
|
||||
BOOL EXIDma(s32 chan, void* buf, s32 len, u32 type, EXICallback callback);
|
||||
BOOL EXISync(s32 chan);
|
||||
EXICallback EXISetExiCallback(s32 chan, EXICallback exiCallback);
|
||||
BOOL EXIProbe(s32 chan);
|
||||
s32 EXIProbeEx(s32 chan);
|
||||
BOOL EXIAttach(s32 chan, EXICallback extCallback);
|
||||
BOOL EXIDetach(s32 chan);
|
||||
BOOL EXISelect(s32 chan, u32 dev, u32 freq);
|
||||
BOOL EXIDeselect(s32 chan);
|
||||
void EXIInit(void);
|
||||
BOOL EXILock(s32 chan, u32 dev, EXICallback unlockedCallback);
|
||||
BOOL EXIUnlock(s32 chan);
|
||||
u32 EXIGetState(s32 chan);
|
||||
static void UnlockedHandler(s32 chan, OSContext* context);
|
||||
s32 EXIGetID(s32 chan, u32 dev, u32* id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* EXIBIOS_H */
|
5
include/dolphin/exi/EXIUart.h
Normal file
5
include/dolphin/exi/EXIUart.h
Normal file
@ -0,0 +1,5 @@
|
||||
#ifndef EXIUART_H
|
||||
#define EXIUART_H
|
||||
|
||||
|
||||
#endif /* EXIUART_H */
|
@ -88,11 +88,16 @@ extern u8 __OSReport_Warning_disable;
|
||||
extern u8 __OSReport_System_disable;
|
||||
extern u8 __OSReport_enable;
|
||||
|
||||
extern BOOL __OSIsGcam;
|
||||
|
||||
extern u32 BOOT_REGION_START : 0x8044babc;
|
||||
extern u32 BOOT_REGION_END : 0x812FDFEC;
|
||||
|
||||
void OSReportInit__Fv(void); // needed for inline asm
|
||||
|
||||
u8* OSGetStackPointer(void);
|
||||
void __OSFPRInit(void);
|
||||
static void InquiryCallback(u32 param_0, DVDCommandBlock* param_1);
|
||||
static void InquiryCallback(s32 param_0, DVDCommandBlock* param_1);
|
||||
void OSInit(void);
|
||||
static void OSExceptionInit(void);
|
||||
void __OSDBIntegrator(void);
|
||||
@ -147,7 +152,7 @@ inline void OSf32tou8(f32* f, u8* out) {
|
||||
*out = __OSf32tou8(*f);
|
||||
}
|
||||
|
||||
inline void OSInitFastCast(void) {
|
||||
static inline void OSInitFastCast(void) {
|
||||
// clang-format off
|
||||
asm {
|
||||
li r3, 4
|
||||
@ -178,16 +183,6 @@ typedef struct OSBootInfo {
|
||||
/* 0x3C */ u32 fst_max_length;
|
||||
} OSBootInfo;
|
||||
|
||||
typedef struct {
|
||||
BOOL valid;
|
||||
u32 restartCode;
|
||||
u32 bootDol;
|
||||
void* regionStart;
|
||||
void* regionEnd;
|
||||
BOOL argsUseDefault;
|
||||
void* argsAddr; // valid only when argsUseDefault = FALSE
|
||||
} OSExecParams;
|
||||
|
||||
typedef struct BI2Debug {
|
||||
/* 0x00 */ s32 debugMonSize;
|
||||
/* 0x04 */ s32 simMemSize;
|
||||
@ -234,7 +229,7 @@ struct GLOBAL_MEMORY {
|
||||
u8 padding_0x30e0[4];
|
||||
u32 field_0x30e4; /* __OSPADButton */
|
||||
u8 padding_0x30ec[8];
|
||||
u32 field_0x30f0; /* DOL Execute Parameters */
|
||||
OSExecParams* field_0x30f0; /* DOL Execute Parameters */
|
||||
u8 padding_0x30f4[12];
|
||||
u32 field_0x3100; /* Physical MEM1 size */
|
||||
u32 field_0x3104; /* Simulated MEM1 size */
|
||||
@ -292,6 +287,7 @@ struct GLOBAL_MEMORY {
|
||||
#define OSUncachedToCached(ucaddr) ((void*)((u8*)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED)))
|
||||
|
||||
extern OSTime __OSStartTime;
|
||||
extern BOOL __OSInIPL;
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
|
@ -7,14 +7,23 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ BOOL valid;
|
||||
/* 0x04 */ u32 restartCode;
|
||||
/* 0x08 */ u32 bootDol;
|
||||
/* 0x0C */ void* regionStart;
|
||||
/* 0x10 */ void* regionEnd;
|
||||
/* 0x18 */ BOOL argsUseDefault;
|
||||
/* 0x14 */ void* argsAddr; // valid only when argsUseDefault = FALSE
|
||||
} OSExecParams;
|
||||
|
||||
static s32 PackArgs(void* param_0, u32 param_1, void* param_2);
|
||||
static void Run(void);
|
||||
static void Run(int param_0);
|
||||
static void ReadDisc(void* param_0, s32 param_1, s32 param_2);
|
||||
static void Callback(void);
|
||||
void __OSGetExecParams(void* param_0);
|
||||
static void GetApploaderPosition(void);
|
||||
void __OSGetExecParams(OSExecParams* param_0);
|
||||
void __OSBootDolSimple(u32 param_0, u32 param_1, void* param_2, void* param_3, s32 param_4, u32 param_5, void* param_6);
|
||||
void __OSBootDol(s32 param_0, u32 param_1, s32 param_2);
|
||||
void __OSBootDol(s32 param_0, u32 param_1, char** param_2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
|
@ -7,9 +7,45 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static u32 GetFontCode(s16 param_0, u32 param_1);
|
||||
typedef enum {
|
||||
OS_FONT_ENCODE_ANSI,
|
||||
OS_FONT_ENCODE_SJIS,
|
||||
OS_FONT_ENCODE_2,
|
||||
OS_FONT_ENCODE_UTF8,
|
||||
OS_FONT_ENCODE_UTF16,
|
||||
OS_FONT_ENCODE_UTF32,
|
||||
OS_FONT_ENCODE_MAX
|
||||
} OSFontEncode;
|
||||
|
||||
typedef struct OSFontHeader {
|
||||
/* 0x00 */ u16 type;
|
||||
/* 0x02 */ u16 firstChar;
|
||||
/* 0x04 */ u16 lastChar;
|
||||
/* 0x06 */ u16 invalidChar;
|
||||
/* 0x08 */ u16 ascent;
|
||||
/* 0x0A */ u16 descent;
|
||||
/* 0x0C */ u16 width;
|
||||
/* 0x0E */ u16 leading;
|
||||
/* 0x10 */ u16 cellWidth;
|
||||
/* 0x12 */ u16 cellHeight;
|
||||
/* 0x14 */ u32 sheetSize;
|
||||
/* 0x18 */ u16 sheetFormat;
|
||||
/* 0x1A */ u16 sheetNumCol;
|
||||
/* 0x1C */ u16 sheetNumRow;
|
||||
/* 0x1E */ u16 sheetWidth;
|
||||
/* 0x20 */ u16 sheetHeight;
|
||||
/* 0x22 */ u16 widthTableOfs;
|
||||
/* 0x24 */ u32 sheetImageOfs;
|
||||
/* 0x28 */ u32 sheetFullSize;
|
||||
/* 0x2C */ u8 c0;
|
||||
/* 0x2D */ u8 c1;
|
||||
/* 0x2E */ u8 c2;
|
||||
/* 0x2F */ u8 c3;
|
||||
} OSFontHeader;
|
||||
|
||||
static u32 GetFontCode(u16 param_0, u16 param_1);
|
||||
u16 OSGetFontEncode(void);
|
||||
static char* ParseStringS(s16 param_0, char* param_1, void* param_2, u32* param_3, u32 param_4, void* param_5);
|
||||
static const u8* ParseStringS(u16 encode, const u8* str, OSFontHeader** fontOut, u32* codeOut);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
|
@ -53,15 +53,18 @@ typedef enum {
|
||||
#define OS_INTERRUPTMASK_MEM_2 OS_INTERRUPTMASK(OS_INTR_MEM_2)
|
||||
#define OS_INTERRUPTMASK_MEM_3 OS_INTERRUPTMASK(OS_INTR_MEM_3)
|
||||
#define OS_INTERRUPTMASK_MEM_ADDRESS OS_INTERRUPTMASK(OS_INTR_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)
|
||||
(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_INTR_DSP_AI)
|
||||
#define OS_INTERRUPTMASK_DSP_ARAM OS_INTERRUPTMASK(OS_INTR_DSP_ARAM)
|
||||
#define OS_INTERRUPTMASK_DSP_DSP OS_INTERRUPTMASK(OS_INTR_DSP_DSP)
|
||||
#define OS_INTERRUPTMASK_DSP \
|
||||
(OS_INTERRUPTMASK_DSP_AI | OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP)
|
||||
(OS_INTERRUPTMASK_DSP_AI | OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP)
|
||||
|
||||
#define OS_INTERRUPTMASK_AI_AI OS_INTERRUPTMASK(OS_INTR_AI_AI)
|
||||
#define OS_INTERRUPTMASK_AI (OS_INTERRUPTMASK_AI_AI)
|
||||
@ -70,21 +73,21 @@ typedef enum {
|
||||
#define OS_INTERRUPTMASK_EXI_0_TC OS_INTERRUPTMASK(OS_INTR_EXI_0_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_0_EXT OS_INTERRUPTMASK(OS_INTR_EXI_0_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_0 \
|
||||
(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT)
|
||||
(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT)
|
||||
|
||||
#define OS_INTERRUPTMASK_EXI_1_EXI OS_INTERRUPTMASK(OS_INTR_EXI_1_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_1_TC OS_INTERRUPTMASK(OS_INTR_EXI_1_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_1_EXT OS_INTERRUPTMASK(OS_INTR_EXI_1_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_1 \
|
||||
(OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT)
|
||||
(OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT)
|
||||
|
||||
#define OS_INTERRUPTMASK_EXI_2_EXI OS_INTERRUPTMASK(OS_INTR_EXI_2_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_2_TC OS_INTERRUPTMASK(OS_INTR_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)
|
||||
(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_INTR_PI_PE_TOKEN)
|
||||
#define OS_INTERRUPTMASK_PI_PE_FINISH OS_INTERRUPTMASK(OS_INTR_PI_PE_FINISH)
|
||||
@ -99,27 +102,27 @@ typedef enum {
|
||||
#define OS_INTERRUPTMASK_PI_DEBUG OS_INTERRUPTMASK(OS_INTR_PI_DEBUG)
|
||||
#define OS_INTERRUPTMASK_PI_HSP OS_INTERRUPTMASK(OS_INTR_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)
|
||||
(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 s16 OSInterrupt;
|
||||
typedef s16 __OSInterrupt;
|
||||
typedef u32 OSInterruptMask;
|
||||
typedef void (*OSInterruptHandler)(OSInterrupt interrupt, OSContext* context);
|
||||
typedef void (*__OSInterruptHandler)(__OSInterrupt interrupt, OSContext* context);
|
||||
|
||||
BOOL OSDisableInterrupts(void);
|
||||
void __RAS_OSDisableInterrupts_end(void);
|
||||
BOOL OSEnableInterrupts(void);
|
||||
BOOL OSRestoreInterrupts(BOOL enable);
|
||||
OSInterruptHandler __OSSetInterruptHandler(OSInterrupt interrupt, OSInterruptHandler handler);
|
||||
OSInterruptHandler __OSGetInterruptHandler(s16 index);
|
||||
__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler);
|
||||
__OSInterruptHandler __OSGetInterruptHandler(s16 index);
|
||||
void __OSInterruptInit(void);
|
||||
static OSInterruptMask SetInterruptMask(OSInterruptMask param_0, OSInterruptMask param_1);
|
||||
OSInterruptMask __OSMaskInterrupts(OSInterruptMask mask);
|
||||
OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask mask);
|
||||
void __OSDispatchInterrupt(u8 interrupt, OSContext* context);
|
||||
static void ExternalInterruptHandler(OSInterrupt interrupt, OSContext* context);
|
||||
static void ExternalInterruptHandler(__OSInterrupt interrupt, OSContext* context);
|
||||
|
||||
void __RAS_OSDisableInterrupts_begin(void);
|
||||
void __RAS_OSDisableInterrupts_end(void);
|
||||
|
@ -1,61 +1,106 @@
|
||||
#ifndef OSLINK_H
|
||||
#define OSLINK_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct OSModuleQueue {
|
||||
int* first;
|
||||
int* last;
|
||||
} OSModuleQueue;
|
||||
#define OS_MODULE_VERSION 3
|
||||
|
||||
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;
|
||||
|
||||
OSModuleQueue __OSModuleList : 0x800030C8;
|
||||
void* __OSStringTable : 0x800030D0;
|
||||
|
||||
typedef struct OSSectionInfo {
|
||||
u32 mOffset;
|
||||
u32 mSize;
|
||||
} OSSectionInfo;
|
||||
struct OSModuleQueue {
|
||||
OSModuleInfo* head;
|
||||
OSModuleInfo* tail;
|
||||
};
|
||||
|
||||
typedef struct OSModuleInfo {
|
||||
u32 mId;
|
||||
u32 mNext;
|
||||
u32 mPrev;
|
||||
u32 mNumSections;
|
||||
struct { // Needed to get an assert correct; very likely bigger
|
||||
u32 sectionInfoOffset;
|
||||
} info;
|
||||
u32 mModuleNameOffset;
|
||||
u32 mModuleNameSize;
|
||||
u32 mModuleVersion;
|
||||
u32 mBssSize;
|
||||
u32 mRelocationTableOffset;
|
||||
u32 mImportTableOffset;
|
||||
u32 mImportTableSize;
|
||||
u8 mPrologSection;
|
||||
u8 mEpilogSection;
|
||||
u8 mUnresolvedSection;
|
||||
u8 mBssSection;
|
||||
u32 prolog;
|
||||
u32 epilog;
|
||||
u32 mUnresolvedFuncOffset;
|
||||
u32 mModuleAlignment;
|
||||
u32 mBssAlignment;
|
||||
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;
|
||||
} OSModuleInfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
BOOL OSLink(OSModuleInfo* module);
|
||||
BOOL OSLinkFixed(OSModuleInfo* module, u32 param_1);
|
||||
#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);
|
||||
static void OSNotifyLink(void);
|
||||
static void OSNotifyUnlink(void);
|
||||
void OSSetStringTable(void* string_table);
|
||||
static BOOL Relocate(OSModuleInfo* param_0, OSModuleInfo* param_1);
|
||||
static BOOL Link(OSModuleInfo* module, u32 param_1);
|
||||
static BOOL Undo(OSModuleInfo* param_0, OSModuleInfo* param_1);
|
||||
void __OSModuleInit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -18,7 +18,7 @@ extern "C" {
|
||||
#define OS_PROTECT_CONTROL_RDWR (OS_PROTECT_CONTROL_READ | OS_PROTECT_CONTROL_WRITE)
|
||||
|
||||
u32 OSGetConsoleSimulatedMemSize();
|
||||
static void MEMIntrruptHandler(OSInterrupt interrupt, struct OSContext* context);
|
||||
static void MEMIntrruptHandler(__OSInterrupt interrupt, struct OSContext* context);
|
||||
void OSProtectRange(u32 channel, void* address, u32 nBytes, u32 control);
|
||||
static void Config24MB(void);
|
||||
static void Config48MB(void);
|
||||
|
@ -22,6 +22,10 @@ typedef struct OSMessageQueue {
|
||||
#define OS_MESSAGE_NOBLOCK 0
|
||||
#define OS_MESSAGE_BLOCK 1
|
||||
|
||||
typedef enum {
|
||||
OS_MSG_PERSISTENT = (1 << 0),
|
||||
} OSMessageFlags;
|
||||
|
||||
void OSInitMessageQueue(OSMessageQueue* queue, OSMessage* msgArray, s32 msgCount);
|
||||
BOOL OSSendMessage(OSMessageQueue* queue, OSMessage msg, s32 flags);
|
||||
BOOL OSReceiveMessage(OSMessageQueue* queue, OSMessage* msg, s32 flags);
|
||||
|
@ -28,7 +28,7 @@ vu32 __PIRegs[12] : 0xCC003000;
|
||||
#define OS_RESET_PRIO_GX 127
|
||||
#define OS_RESET_PRIO_ALARM 4294967295
|
||||
|
||||
typedef s32 (*OSResetFunction)(s32);
|
||||
typedef BOOL (*OSResetFunction)(BOOL final);
|
||||
|
||||
typedef struct OSResetFunctionInfo {
|
||||
/* 0x0 */ OSResetFunction func;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef OSRESETSW_H
|
||||
#define OSRESETSW_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
#include "dolphin/os/OSInterrupt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -11,6 +11,7 @@ typedef void (*OSResetCallback)(void);
|
||||
|
||||
static BOOL OSGetResetButtonState(void);
|
||||
BOOL OSGetResetSwitchState(void);
|
||||
void __OSResetSWInterruptHandler(__OSInterrupt interrupt, OSContext* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
|
@ -68,7 +68,7 @@ struct OSThread {
|
||||
OSMutexQueue owned_mutexes;
|
||||
OSThreadLink active_threads_link;
|
||||
u8* stack_base;
|
||||
u8* stack_end;
|
||||
u32* stack_end;
|
||||
u8* error_code;
|
||||
void* data[2];
|
||||
};
|
||||
|
@ -1,5 +0,0 @@
|
||||
#ifndef __PPC_EABI_INIT_H
|
||||
#define __PPC_EABI_INIT_H
|
||||
|
||||
|
||||
#endif /* __PPC_EABI_INIT_H */
|
@ -76,6 +76,8 @@ static void PADProbeCallback(s32 chan, u32 error, OSContext* context);
|
||||
static void PADTypeAndStatusCallback(s32 chan, u32 type);
|
||||
static void PADReceiveCheckCallback(s32 chan, u32 type);
|
||||
|
||||
extern u32 __PADSpec;
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
@ -102,10 +102,10 @@ typedef union SIComm_u {
|
||||
|
||||
BOOL SIBusy(void);
|
||||
BOOL SIIsChanBusy(s32 chan);
|
||||
static void SIInterruptHandler(OSInterrupt interrupt, OSContext* context);
|
||||
static void SIInterruptHandler(__OSInterrupt interrupt, OSContext* context);
|
||||
static BOOL SIEnablePollingInterrupt(BOOL enable);
|
||||
BOOL SIRegisterPollingHandler(OSInterruptHandler handler);
|
||||
BOOL SIUnregisterPollingHandler(OSInterruptHandler handler);
|
||||
BOOL SIRegisterPollingHandler(__OSInterruptHandler handler);
|
||||
BOOL SIUnregisterPollingHandler(__OSInterruptHandler handler);
|
||||
void SIInit(void);
|
||||
u32 SIGetStatus(s32 chan);
|
||||
void SISetCommand(s32 chan, u32 command);
|
||||
|
@ -4,14 +4,12 @@
|
||||
*/
|
||||
|
||||
#include "DynamicLink.h"
|
||||
#include "JSystem/JKernel/JKRArchive.h"
|
||||
#include "JSystem/JKernel/JKRDvdRipper.h"
|
||||
#include "JSystem/JKernel/JKRExpHeap.h"
|
||||
#include "JSystem/JKernel/JKRFileCache.h"
|
||||
#include "JSystem/JUtility/JUTAssert.h"
|
||||
#include "JSystem/JUtility/JUTConsole.h"
|
||||
#include "stdio.h"
|
||||
#include "REL/executor.h"
|
||||
#include "m_Do/m_Do_dvd_thread.h"
|
||||
#include "m_Do/m_Do_ext.h"
|
||||
#include "m_Do/m_Do_printf.h"
|
||||
@ -51,8 +49,6 @@ DynamicModuleControlBase::DynamicModuleControlBase() {
|
||||
mLast = this;
|
||||
}
|
||||
|
||||
extern OSThread mainThread;
|
||||
|
||||
BOOL DynamicModuleControlBase::link() {
|
||||
OSThread* thread = OSGetCurrentThread();
|
||||
if (thread != &mainThread) {
|
||||
@ -64,12 +60,12 @@ BOOL DynamicModuleControlBase::link() {
|
||||
if (do_link() == false) {
|
||||
return false;
|
||||
}
|
||||
if (mDoLinkCount < 65535) {
|
||||
if (mDoLinkCount < 0xFFFF) {
|
||||
mDoLinkCount++;
|
||||
}
|
||||
}
|
||||
JUT_ASSERT(100, mLinkCount < 65535);
|
||||
if (mLinkCount < 65535) {
|
||||
if (mLinkCount < 0xFFFF) {
|
||||
mLinkCount++;
|
||||
}
|
||||
return true;
|
||||
@ -212,19 +208,19 @@ bool DynamicModuleControl::do_load() {
|
||||
snprintf(buffer, 64, "%s.rel", mName);
|
||||
if (mModule == NULL && sArchive != NULL) {
|
||||
if (mModule == NULL) {
|
||||
mModule = (OSModuleInfo*)JKRGetResource('MMEM', buffer, sArchive);
|
||||
mModule = (OSModuleHeader*)JKRGetResource('MMEM', buffer, sArchive);
|
||||
if (mModule != NULL) {
|
||||
mResourceType = 1;
|
||||
}
|
||||
}
|
||||
if (mModule == NULL) {
|
||||
mModule = (OSModuleInfo*)JKRGetResource('AMEM', buffer, sArchive);
|
||||
mModule = (OSModuleHeader*)JKRGetResource('AMEM', buffer, sArchive);
|
||||
if (mModule != NULL) {
|
||||
mResourceType = 2;
|
||||
}
|
||||
}
|
||||
if (mModule == NULL) {
|
||||
mModule = (OSModuleInfo*)JKRGetResource('DMEM', buffer, sArchive);
|
||||
mModule = (OSModuleHeader*)JKRGetResource('DMEM', buffer, sArchive);
|
||||
if (mModule != NULL) {
|
||||
mResourceType = 3;
|
||||
}
|
||||
@ -236,7 +232,7 @@ bool DynamicModuleControl::do_load() {
|
||||
} else {
|
||||
if (mModule == NULL) {
|
||||
snprintf(buffer, 64, "/rels/%s.rel", mName);
|
||||
mModule = (OSModuleInfo*)JKRDvdToMainRam(
|
||||
mModule = (OSModuleHeader*)JKRDvdToMainRam(
|
||||
buffer, NULL, EXPAND_SWITCH_UNKNOWN1, NULL, archiveHeap,
|
||||
JKRDvdRipper::ALLOC_DIRECTION_FORWARD, 0, NULL);
|
||||
if (mModule != NULL) {
|
||||
@ -245,7 +241,7 @@ bool DynamicModuleControl::do_load() {
|
||||
}
|
||||
}
|
||||
if (mModule == NULL && sFileCache != NULL) {
|
||||
mModule = (OSModuleInfo*)sFileCache->getResource('rels', buffer);
|
||||
mModule = (OSModuleHeader*)sFileCache->getResource('rels', buffer);
|
||||
if (mModule != NULL) {
|
||||
mSize = 0;
|
||||
mResourceType = 11;
|
||||
@ -254,7 +250,7 @@ bool DynamicModuleControl::do_load() {
|
||||
}
|
||||
}
|
||||
if (mModule == NULL) {
|
||||
// "DynamicModuleControl::do_load() Resource loading failure [%s]\n"
|
||||
// "DynamicModuleControl::do_load() Resource load failure [%s]\n"
|
||||
OSReport_Error("DynamicModuleControl::do_load() リソース読み込み失敗 [%s]\n", mName);
|
||||
return false;
|
||||
}
|
||||
@ -297,8 +293,7 @@ BOOL DynamicModuleControl::do_load_async() {
|
||||
if (mModule != NULL) {
|
||||
return true;
|
||||
}
|
||||
mAsyncLoadCallback = mDoDvdThd_callback_c::create(
|
||||
(mDoDvdThd_callback_func)DynamicModuleControl::callback, this);
|
||||
mAsyncLoadCallback = mDoDvdThd_callback_c::create((mDoDvdThd_callback_func)DynamicModuleControl::callback, this);
|
||||
if (mAsyncLoadCallback == NULL) {
|
||||
OSReport_Error(
|
||||
// "DynamicModuleControl::do_load_async() async load callback entry failure [%s]\n"
|
||||
@ -326,9 +321,9 @@ bool DynamicModuleControl::do_unload() {
|
||||
void DynamicModuleControl::dump2() {
|
||||
if (mModule != NULL) {
|
||||
OSSectionInfo* section = (OSSectionInfo*)mModule->info.sectionInfoOffset;
|
||||
OSReport("mModule=%08x %08x %08x %08x %08x\n", mModule, section[1].mOffset & ~1,
|
||||
section[1].mSize, mModule->mImportTableOffset - mModule->mRelocationTableOffset,
|
||||
mModule->mImportTableSize);
|
||||
OSReport("mModule=%08x %08x %08x %08x %08x\n", mModule, section[1].offset & ~1,
|
||||
section[1].size, mModule->impOffset - mModule->relOffset,
|
||||
mModule->impSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,57 +337,57 @@ BOOL DynamicModuleControl::do_link() {
|
||||
JUT_ASSERT(615, (u32)mModule + mModule->fixSize < 0x82000000);
|
||||
OSGetTime();
|
||||
OSGetTime();
|
||||
if (mModule->mModuleVersion >= 3) {
|
||||
if (mModule->info.version >= 3) {
|
||||
u32 fixSizePtr;
|
||||
u32 fixSize = mModule->fixSize;
|
||||
u32 fixSize2 = (fixSize + 0x1f) & ~0x1f;
|
||||
fixSizePtr = (u32)mModule + fixSize2;
|
||||
s32 size = JKRGetMemBlockSize(NULL, mModule);
|
||||
if (size < 0) {
|
||||
void* bss = JKRAlloc(mModule->mBssSize, 0x20);
|
||||
void* bss = JKRAlloc(mModule->bssSize, 0x20);
|
||||
if (bss == NULL) {
|
||||
// "BSS Memory allocation failed\n"
|
||||
OSReport_Error("BSSメモリ確保失敗\n", bss);
|
||||
goto error;
|
||||
}
|
||||
mBss = bss;
|
||||
BOOL linkResult = OSLink(mModule);
|
||||
BOOL linkResult = OSLink(&mModule->info, bss);
|
||||
if (linkResult == FALSE) {
|
||||
// "link failed\n"
|
||||
OSReport_Error("リンク失敗\n");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (fixSize2 + mModule->mBssSize < size) {
|
||||
BOOL linkResult = OSLinkFixed(mModule, fixSizePtr);
|
||||
if (fixSize2 + mModule->bssSize < size) {
|
||||
BOOL linkResult = OSLinkFixed(&mModule->info, (void*)fixSizePtr);
|
||||
if (linkResult == FALSE) {
|
||||
// "link failed\n"
|
||||
OSReport_Error("リンク失敗\n");
|
||||
goto error;
|
||||
}
|
||||
s32 result = JKRResizeMemBlock(NULL, mModule, fixSize2 + mModule->mBssSize);
|
||||
s32 result = JKRResizeMemBlock(NULL, mModule, fixSize2 + mModule->bssSize);
|
||||
if (result < 0) {
|
||||
// "Module size (resize) failed\n"
|
||||
OSReport_Error("モジュールリサイズ(縮小)失敗\n");
|
||||
}
|
||||
} else {
|
||||
s32 result = JKRResizeMemBlock(NULL, mModule, fixSize2 + mModule->mBssSize);
|
||||
s32 result = JKRResizeMemBlock(NULL, mModule, fixSize2 + mModule->bssSize);
|
||||
if (result > 0) {
|
||||
BOOL linkResult = OSLinkFixed(mModule, fixSizePtr);
|
||||
BOOL linkResult = OSLinkFixed(&mModule->info, (void*)fixSizePtr);
|
||||
if (linkResult == FALSE) {
|
||||
// "link failed\n"
|
||||
OSReport_Error("リンク失敗\n");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
void* bss = JKRAlloc(mModule->mBssSize, 0x20);
|
||||
void* bss = JKRAlloc(mModule->bssSize, 0x20);
|
||||
if (bss == NULL) {
|
||||
// "BSS Memory allocation failure [%x]\n"
|
||||
OSReport_Error("BSSメモリ確保失敗 [%x]\n", mModule->mBssSize);
|
||||
OSReport_Error("BSSメモリ確保失敗 [%x]\n", mModule->bssSize);
|
||||
goto error;
|
||||
}
|
||||
mBss = bss;
|
||||
BOOL linkResult = OSLinkFixed(mModule, (u32)bss);
|
||||
BOOL linkResult = OSLinkFixed(&mModule->info, bss);
|
||||
if (linkResult == FALSE) {
|
||||
// "link failed\n"
|
||||
OSReport_Error("リンク失敗\n");
|
||||
@ -434,7 +429,7 @@ bool DynamicModuleControl::do_unlink() {
|
||||
OSTime time1 = OSGetTime();
|
||||
((void (*)())mModule->epilog)();
|
||||
OSTime time2 = OSGetTime();
|
||||
BOOL unklink = OSUnlink(mModule);
|
||||
BOOL unklink = OSUnlink(&mModule->info);
|
||||
OSTime time3 = OSGetTime();
|
||||
if (unklink == FALSE) {
|
||||
// "Unlink failed mModule=%08x mBss=%08x\n"
|
||||
@ -456,7 +451,7 @@ int DynamicModuleControl::getModuleSize() const {
|
||||
if (mBss != NULL) {
|
||||
JKRGetMemBlockSize(NULL, mBss);
|
||||
}
|
||||
return size + mModule->mBssSize;
|
||||
return size + mModule->bssSize;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@ -467,15 +462,15 @@ const char* DynamicModuleControl::getModuleTypeString() const {
|
||||
return strings[mResourceType & 3];
|
||||
}
|
||||
|
||||
void ModuleProlog() {
|
||||
extern "C" void ModuleProlog() {
|
||||
/* empty function */
|
||||
}
|
||||
|
||||
void ModuleEpilog() {
|
||||
extern "C" void ModuleEpilog() {
|
||||
/* empty function */
|
||||
}
|
||||
|
||||
void ModuleUnresolved() {
|
||||
extern "C" void ModuleUnresolved() {
|
||||
// "\nError: Unlinked function was called.\n"
|
||||
OSReport_Error("\nError: リンクされていない関数が呼び出されました.\n");
|
||||
OSReport_Error("Address: Back Chain LR Save\n");
|
||||
@ -488,7 +483,7 @@ void ModuleUnresolved() {
|
||||
OSReport_Error("\n");
|
||||
}
|
||||
|
||||
void ModuleConstructorsX(const VoidFunc* _ctors) {
|
||||
extern "C" void ModuleConstructorsX(void (**_ctors)()) {
|
||||
JUT_ASSERT(850, _ctors);
|
||||
while (*_ctors != 0) {
|
||||
(**_ctors)();
|
||||
@ -496,7 +491,7 @@ void ModuleConstructorsX(const VoidFunc* _ctors) {
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleDestructorsX(const VoidFunc* _dtors) {
|
||||
extern "C" void ModuleDestructorsX(void (**_dtors)()) {
|
||||
JUT_ASSERT(864, _dtors);
|
||||
while (*_dtors != 0) {
|
||||
(**_dtors)();
|
||||
|
@ -265,20 +265,20 @@ bool JUTException::searchPartialModule(u32 address, u32* module_id, u32* section
|
||||
}
|
||||
|
||||
OSModuleInfo* module = *(OSModuleInfo**)0x800030C8;
|
||||
for (; module != NULL; module = (OSModuleInfo*)module->mNext) {
|
||||
OSSectionInfo* section = (OSSectionInfo*)module->info.sectionInfoOffset;
|
||||
for (u32 i = 0; i < module->mNumSections; section++, i++) {
|
||||
if (section->mSize != 0) {
|
||||
u32 addr = section->mOffset & ~0x01;
|
||||
if ((addr <= address) && (address < addr + section->mSize)) {
|
||||
for (; module != NULL; module = (OSModuleInfo*)module->link.next) {
|
||||
OSSectionInfo* section = (OSSectionInfo*)module->sectionInfoOffset;
|
||||
for (u32 i = 0; i < module->numSections; section++, i++) {
|
||||
if (section->size != 0) {
|
||||
u32 addr = section->offset & ~0x01;
|
||||
if ((addr <= address) && (address < addr + section->size)) {
|
||||
if (module_id)
|
||||
*module_id = module->mId;
|
||||
*module_id = module->id;
|
||||
if (section_id)
|
||||
*section_id = i;
|
||||
if (section_offset)
|
||||
*section_offset = address - addr;
|
||||
if (name_offset)
|
||||
*name_offset = module->mModuleNameOffset;
|
||||
*name_offset = module->nameOffset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ static GBASecParam SecParams[4];
|
||||
GBAControl __GBA[4];
|
||||
BOOL __GBAReset = FALSE;
|
||||
|
||||
static s32 OnReset(s32);
|
||||
static BOOL OnReset(BOOL final);
|
||||
|
||||
static OSResetFunctionInfo ResetFunctionInfo = {OnReset, 127};
|
||||
|
||||
@ -87,7 +87,7 @@ s32 GBAReset(s32 chan, u8* status) {
|
||||
return __GBASync(chan);
|
||||
}
|
||||
|
||||
s32 OnReset(s32) {
|
||||
BOOL OnReset(BOOL final) {
|
||||
__GBAReset = TRUE;
|
||||
return TRUE;
|
||||
}
|
661
src/dolphin/os/OS.c
Normal file
661
src/dolphin/os/OS.c
Normal file
@ -0,0 +1,661 @@
|
||||
//
|
||||
// OS
|
||||
//
|
||||
|
||||
#include "dolphin/os/OS.h"
|
||||
#include "dolphin/base/PPCArch.h"
|
||||
// #include "dolphin/db.h"
|
||||
#include "dolphin/pad/Pad.h"
|
||||
#include "dolphin/dvd/dvdfs.h"
|
||||
// #include "TRK_MINNOW_DOLPHIN/Os/dolphin/dolphin_trk.h"
|
||||
|
||||
#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
|
||||
|
||||
#define OS_EXCEPTIONTABLE_ADDR 0x3000
|
||||
#define OS_DBJUMPPOINT_ADDR 0x60
|
||||
#define OS_CURRENTCONTEXT_PADDR 0xC0
|
||||
|
||||
//
|
||||
// External References:
|
||||
//
|
||||
|
||||
void _epilog();
|
||||
|
||||
static OSBootInfo* BootInfo;
|
||||
|
||||
static volatile u32* BI2DebugFlag;
|
||||
|
||||
static u32* BI2DebugFlagHolder;
|
||||
|
||||
OSTime __OSStartTime;
|
||||
|
||||
BOOL __OSInIPL;
|
||||
|
||||
extern OSExceptionHandler* OSExceptionTable;
|
||||
OSExceptionHandler* OSExceptionTable;
|
||||
|
||||
extern BOOL AreWeInitialized;
|
||||
BOOL AreWeInitialized;
|
||||
|
||||
extern f64 ZeroPS;
|
||||
f64 ZeroPS;
|
||||
|
||||
extern f64 ZeroF;
|
||||
f64 ZeroF;
|
||||
|
||||
BOOL __OSIsGcam;
|
||||
|
||||
asm void __OSFPRInit(void) {
|
||||
// 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
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
u32 OSGetConsoleType(void) {
|
||||
if (BootInfo == NULL || BootInfo->console_type == 0) {
|
||||
return OS_CONSOLE_ARTHUR;
|
||||
}
|
||||
|
||||
return BootInfo->console_type;
|
||||
}
|
||||
|
||||
static DVDDriveInfo DriveInfo;
|
||||
|
||||
void* __OSSavedRegionStart;
|
||||
void* __OSSavedRegionEnd;
|
||||
|
||||
extern OSExecParams __OSRebootParams;
|
||||
|
||||
static inline void ClearArena(void) {
|
||||
BOOL var_r0;
|
||||
if (OSGetResetCode() & 0x80000000) {
|
||||
var_r0 = TRUE;
|
||||
} else {
|
||||
var_r0 = FALSE;
|
||||
}
|
||||
|
||||
if (!var_r0) {
|
||||
memset(OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
if (*(u32*)&__OSRebootParams.regionStart == 0U) {
|
||||
memset(OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
if ((u32)OSGetArenaLo() < *(u32*)&__OSRebootParams.regionStart) {
|
||||
if ((u32)OSGetArenaHi() <= *(u32*)&__OSRebootParams.regionStart) {
|
||||
memset((u32)OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
memset(OSGetArenaLo(), 0U, *(u32*)&__OSRebootParams.regionStart - (u32)OSGetArenaLo());
|
||||
|
||||
if ((u32)OSGetArenaHi() > *(u32*)&__OSRebootParams.regionEnd) {
|
||||
memset(*(u32*)&__OSRebootParams.regionEnd, 0,
|
||||
(u32)OSGetArenaHi() - *(u32*)&__OSRebootParams.regionEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void InquiryCallback(s32 result, DVDCommandBlock* block) {
|
||||
switch (block->state) {
|
||||
case 0:
|
||||
__OSDeviceCode = (u16)(0x8000 | DriveInfo.device_code);
|
||||
break;
|
||||
default:
|
||||
__OSDeviceCode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 DriveBlock[48];
|
||||
|
||||
OSExecParams __OSRebootParams;
|
||||
|
||||
static const char* __OSVersion = "<< Dolphin SDK - OS release build: Nov 10 2004 06:26:41 (0x2301) >>";
|
||||
|
||||
extern u8 __ArenaHi[];
|
||||
extern u8 __ArenaLo[];
|
||||
extern void* _stack_end;
|
||||
extern char _db_stack_end[];
|
||||
|
||||
void OSInit(void) {
|
||||
/*
|
||||
Initializes the Dolphin operating system.
|
||||
- most of the main operations get farmed out to other functions
|
||||
- loading debug info and setting up heap bounds largely happen here
|
||||
- a lot of OS reporting also gets controlled here
|
||||
*/
|
||||
|
||||
BI2Debug* DebugInfo;
|
||||
void* debugArenaLo;
|
||||
u32 inputConsoleType;
|
||||
u32 tdev;
|
||||
|
||||
if ((BOOL)AreWeInitialized == FALSE) {
|
||||
AreWeInitialized = TRUE;
|
||||
|
||||
// SYSTEM //
|
||||
__OSStartTime = __OSGetSystemTime();
|
||||
OSDisableInterrupts();
|
||||
|
||||
__OSGetExecParams(&__OSRebootParams);
|
||||
PPCMtmmcr0(0);
|
||||
PPCMtmmcr1(0);
|
||||
PPCMtpmc1(0);
|
||||
PPCMtpmc2(0);
|
||||
PPCMtpmc3(0);
|
||||
PPCMtpmc4(0);
|
||||
PPCDisableSpeculation();
|
||||
PPCSetFpNonIEEEMode();
|
||||
|
||||
// DEBUG //
|
||||
BI2DebugFlag = 0; // debug flag from the DVD BI2 header
|
||||
BootInfo = (OSBootInfo*)OS_BASE_CACHED; // set pointer to BootInfo
|
||||
|
||||
__DVDLongFileNameFlag =
|
||||
(u32)0; // flag to tell us whether we make it through the debug loading
|
||||
|
||||
// time to grab a bunch of debug info from the DVD
|
||||
// the address for where the BI2 debug info is, is stored at OS_BI2_DEBUG_ADDRESS
|
||||
DebugInfo = (BI2Debug*)*((u32*)OS_BI2_DEBUG_ADDRESS);
|
||||
|
||||
if (DebugInfo != NULL) {
|
||||
BI2DebugFlag = &DebugInfo->debugFlag; // debug flag from DVD BI2
|
||||
__PADSpec = (u32)DebugInfo->padSpec; // some other info from DVD BI2
|
||||
*((u8*)DEBUGFLAG_ADDR) = (u8)*BI2DebugFlag; // store flag in mem
|
||||
*((u8*)OS_DEBUG_ADDRESS_2) = (u8)__PADSpec; // store other info in mem
|
||||
} else if (BootInfo->arena_hi) {
|
||||
BI2DebugFlagHolder =
|
||||
(u32*)*((u8*)DEBUGFLAG_ADDR); // grab whatever's stored at 0x800030E8
|
||||
BI2DebugFlag = (u32*)&BI2DebugFlagHolder; // flag is then address of flag holder
|
||||
__PADSpec = (u32) * ((u8*)OS_DEBUG_ADDRESS_2); // pad spec is whatever's at 0x800030E9
|
||||
}
|
||||
|
||||
__DVDLongFileNameFlag = 1;
|
||||
|
||||
// HEAP //
|
||||
OSSetArenaLo((BootInfo->arena_lo == NULL) ? __ArenaLo : BootInfo->arena_lo);
|
||||
|
||||
// if the input arenaLo is null, and debug flag location exists (and flag is < 2),
|
||||
// set arenaLo to just past the end of the db stack
|
||||
if ((BootInfo->arena_lo == NULL) && (BI2DebugFlag != 0) && (*BI2DebugFlag < 2)) {
|
||||
debugArenaLo = (char*)(((u32)_db_stack_end + 0x1f) & ~0x1f);
|
||||
OSSetArenaLo(debugArenaLo);
|
||||
}
|
||||
|
||||
OSSetArenaHi((BootInfo->arena_hi == NULL) ? __ArenaHi : BootInfo->arena_hi);
|
||||
|
||||
// OS INIT AND REPORT //
|
||||
OSExceptionInit();
|
||||
__OSInitSystemCall();
|
||||
OSInitAlarm();
|
||||
__OSModuleInit();
|
||||
__OSInterruptInit();
|
||||
__OSSetInterruptHandler(OS_INTR_PI_RSW, (void*)__OSResetSWInterruptHandler);
|
||||
__OSContextInit();
|
||||
__OSCacheInit();
|
||||
EXIInit();
|
||||
SIInit();
|
||||
__OSInitSram();
|
||||
__OSThreadInit();
|
||||
__OSInitAudioSystem();
|
||||
PPCMthid2(PPCMfhid2() & 0xBFFFFFFF);
|
||||
if ((BOOL)__OSInIPL == FALSE) {
|
||||
__OSInitMemoryProtection();
|
||||
}
|
||||
|
||||
OSReport("\nDolphin OS\n");
|
||||
OSReport("Kernel built : %s %s\n", "Nov 10 2004", "06:26:41");
|
||||
OSReport("Console Type : ");
|
||||
|
||||
if (BootInfo == NULL || (inputConsoleType = BootInfo->console_type) == 0) {
|
||||
inputConsoleType = OS_CONSOLE_ARTHUR; // default console type
|
||||
} else {
|
||||
inputConsoleType = BootInfo->console_type;
|
||||
}
|
||||
|
||||
switch (inputConsoleType & 0xF0000000) {
|
||||
case OS_CONSOLE_RETAIL:
|
||||
OSReport("Retail %d\n", inputConsoleType);
|
||||
break;
|
||||
case OS_CONSOLE_DEVELOPMENT:
|
||||
case OS_CONSOLE_TDEV:
|
||||
switch (inputConsoleType & 0x0FFFFFFF) {
|
||||
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:
|
||||
tdev = (u32)inputConsoleType & 0x0FFFFFFF;
|
||||
OSReport("Development HW%d (%08x)\n", tdev - 3, inputConsoleType);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OSReport("%08x\n", inputConsoleType);
|
||||
break;
|
||||
}
|
||||
|
||||
OSReport("Memory %d MB\n", (u32)BootInfo->memory_size >> 0x14U);
|
||||
OSReport("Arena : 0x%x - 0x%x\n", OSGetArenaLo(), OSGetArenaHi());
|
||||
OSRegisterVersion(__OSVersion);
|
||||
|
||||
if (BI2DebugFlag && ((*BI2DebugFlag) >= 2)) {
|
||||
EnableMetroTRKInterrupts();
|
||||
}
|
||||
|
||||
ClearArena();
|
||||
OSEnableInterrupts();
|
||||
|
||||
if ((BOOL)__OSInIPL == FALSE) {
|
||||
DVDInit();
|
||||
if ((BOOL)__OSIsGcam) {
|
||||
__OSDeviceCode = 0x9000;
|
||||
return;
|
||||
}
|
||||
DCInvalidateRange(&DriveInfo, sizeof(DriveInfo));
|
||||
DVDInquiryAsync((DVDCommandBlock*)&DriveBlock, &DriveInfo, InquiryCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u32 __OSExceptionLocations[] = {
|
||||
0x00000100, // 0 System reset
|
||||
0x00000200, // 1 Machine check
|
||||
0x00000300, // 2 DSI - seg fault or DABR
|
||||
0x00000400, // 3 ISI
|
||||
0x00000500, // 4 External interrupt
|
||||
0x00000600, // 5 Alignment
|
||||
0x00000700, // 6 Program
|
||||
0x00000800, // 7 FP Unavailable
|
||||
0x00000900, // 8 Decrementer
|
||||
0x00000C00, // 9 System call
|
||||
0x00000D00, // 10 Trace
|
||||
0x00000F00, // 11 Performance monitor
|
||||
0x00001300, // 12 Instruction address breakpoint.
|
||||
0x00001400, // 13 System management interrupt
|
||||
0x00001700 // 14 Thermal interrupt
|
||||
};
|
||||
|
||||
// dummy entry points to the OS Exception vector
|
||||
void __OSEVStart(void);
|
||||
void __OSDBINTSTART(void);
|
||||
void __OSDBINTEND(void);
|
||||
void __OSDBJUMPSTART(void);
|
||||
void __OSDBJUMPEND(void);
|
||||
|
||||
#define NOP 0x60000000
|
||||
|
||||
static void OSExceptionInit(void) {
|
||||
__OSException exception;
|
||||
void* destAddr;
|
||||
|
||||
// These two vars help us change the exception number embedded
|
||||
// in the exception handler code.
|
||||
u32* opCodeAddr;
|
||||
u32 oldOpCode;
|
||||
|
||||
// Address range of the actual code to be copied.
|
||||
u8* handlerStart;
|
||||
u32 handlerSize;
|
||||
|
||||
// Install the first level exception vector.
|
||||
opCodeAddr = (u32*)__OSEVSetNumber;
|
||||
oldOpCode = *opCodeAddr;
|
||||
handlerStart = (u8*)__OSEVStart;
|
||||
handlerSize = (u32)((u8*)__OSEVEnd - (u8*)__OSEVStart);
|
||||
|
||||
// Install the DB integrator, only if we are the first OSInit to be run
|
||||
destAddr = (void*)OSPhysicalToCached(OS_DBJUMPPOINT_ADDR);
|
||||
if (*(u32*)destAddr == 0) // Lomem should be zero cleared only once by BS2
|
||||
{
|
||||
DBPrintf("Installing OSDBIntegrator\n");
|
||||
memcpy(destAddr, (void*)__OSDBINTSTART, (u32)__OSDBINTEND - (u32)__OSDBINTSTART);
|
||||
DCFlushRangeNoSync(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART);
|
||||
__sync();
|
||||
ICInvalidateRange(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART);
|
||||
}
|
||||
|
||||
// Copy the right vector into the table
|
||||
for (exception = 0; exception < 15; exception++) {
|
||||
if (BI2DebugFlag && (*BI2DebugFlag >= 2) && __DBIsExceptionMarked(exception)) {
|
||||
// this DBPrintf is suspicious.
|
||||
DBPrintf(">>> OSINIT: exception %d commandeered by TRK\n", exception);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Modify the copy of code in text before transferring
|
||||
// to the exception table.
|
||||
*opCodeAddr = oldOpCode | exception;
|
||||
|
||||
// Modify opcodes at __DBVECTOR if necessary
|
||||
if (__DBIsExceptionMarked(exception)) {
|
||||
DBPrintf(">>> OSINIT: exception %d vectored to debugger\n", exception);
|
||||
memcpy((void*)__DBVECTOR, (void*)__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 = OSPhysicalToCached(OS_EXCEPTIONTABLE_ADDR);
|
||||
|
||||
// install default exception handlers
|
||||
for (exception = 0; exception < 15; exception++) {
|
||||
__OSSetExceptionHandler(exception, OSDefaultExceptionHandler);
|
||||
}
|
||||
|
||||
// restore the old opcode, so that we can re-start an application without
|
||||
// downloading the text segments
|
||||
*opCodeAddr = oldOpCode;
|
||||
|
||||
DBPrintf("Exceptions initialized...\n");
|
||||
}
|
||||
|
||||
asm void __OSDBIntegrator(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
entry __OSDBINTSTART
|
||||
li r5, 0x40
|
||||
mflr r3
|
||||
stw r3, 0xc(r5)
|
||||
lwz r3, 8(r5)
|
||||
oris r3, r3, 0x8000
|
||||
mtlr r3
|
||||
li r3, 0x30
|
||||
mtmsr r3
|
||||
blr
|
||||
entry __OSDBINTEND
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void __OSDBJump(void){
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
entry __OSDBJUMPSTART
|
||||
bla 0x60
|
||||
entry __OSDBJUMPEND
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
OSExceptionHandler __OSSetExceptionHandler(__OSException exception, OSExceptionHandler handler) {
|
||||
OSExceptionHandler old = OSExceptionTable[exception];
|
||||
OSExceptionTable[exception] = handler;
|
||||
return old;
|
||||
}
|
||||
|
||||
OSExceptionHandler __OSGetExceptionHandler(__OSException exception) {
|
||||
return OSExceptionTable[exception];
|
||||
}
|
||||
|
||||
static asm void OSExceptionVector(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
entry __OSEVStart
|
||||
// Save r4 into SPRG0
|
||||
mtsprg 0, r4
|
||||
|
||||
// Load current context physical address into r4
|
||||
lwz r4, OS_CURRENTCONTEXT_PADDR
|
||||
|
||||
// Save r3 - r5 into the current context
|
||||
stw r3, OS_CONTEXT_R3(r4)
|
||||
mfsprg r3, 0
|
||||
stw r3, OS_CONTEXT_R4(r4)
|
||||
stw r5, OS_CONTEXT_R5(r4)
|
||||
|
||||
lhz r3, OS_CONTEXT_STATE(r4)
|
||||
ori r3, r3, OS_CONTEXT_STATE_EXC
|
||||
sth r3, OS_CONTEXT_STATE(r4)
|
||||
|
||||
// Save misc registers
|
||||
mfcr r3
|
||||
stw r3, OS_CONTEXT_CR(r4)
|
||||
mflr r3
|
||||
stw r3, OS_CONTEXT_LR(r4)
|
||||
mfctr r3
|
||||
stw r3, OS_CONTEXT_CTR(r4)
|
||||
mfxer r3
|
||||
stw r3, OS_CONTEXT_XER(r4)
|
||||
mfsrr0 r3
|
||||
stw r3, OS_CONTEXT_SRR0(r4)
|
||||
mfsrr1 r3
|
||||
stw r3, OS_CONTEXT_SRR1(r4)
|
||||
mr r5, r3
|
||||
|
||||
entry __DBVECTOR
|
||||
nop
|
||||
|
||||
// Set SRR1[IR|DR] to turn on address
|
||||
// translation at the next RFI
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
// This lets us change the exception number based on the
|
||||
// exception we're installing.
|
||||
entry __OSEVSetNumber
|
||||
li r3, 0
|
||||
|
||||
// Load current context virtual address into r4
|
||||
lwz r4, 0xd4(r0)
|
||||
|
||||
// Check non-recoverable interrupt
|
||||
rlwinm. r5, r5, 0, MSR_RI_BIT, MSR_RI_BIT
|
||||
bne recoverable
|
||||
lis r5, OSDefaultExceptionHandler@ha
|
||||
addi r5, r5, OSDefaultExceptionHandler@l
|
||||
mtsrr0 r5
|
||||
rfi
|
||||
// NOT REACHED HERE
|
||||
|
||||
recoverable:
|
||||
// Locate exception handler.
|
||||
rlwinm r5, r3, 2, 0x16, 0x1d // 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 enabled, not yet recoverable
|
||||
|
||||
rfi
|
||||
// NOT REACHED HERE
|
||||
// The handler will restore state
|
||||
|
||||
entry __OSEVEnd
|
||||
nop
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static asm void OSDefaultExceptionHandler(register __OSException exception,
|
||||
register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
stw r0, 0(context)
|
||||
stw r1, 4(context)
|
||||
stw r2, 8(context)
|
||||
stmw r6, 0x18(context)
|
||||
mfspr r0, 0x391
|
||||
stw r0, 0x1a8(context)
|
||||
mfspr r0, 0x392
|
||||
stw r0, 0x1ac(context)
|
||||
mfspr r0, 0x393
|
||||
stw r0, 0x1b0(context)
|
||||
mfspr r0, 0x394
|
||||
stw r0, 0x1b4(context)
|
||||
mfspr r0, 0x395
|
||||
stw r0, 0x1b8(context)
|
||||
mfspr r0, 0x396
|
||||
stw r0, 0x1bc(context)
|
||||
mfspr r0, 0x397
|
||||
stw r0, 0x1c0(context)
|
||||
|
||||
mfdsisr r5
|
||||
mfdar r6
|
||||
|
||||
stwu r1, -8(r1)
|
||||
b __OSUnhandledException
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void __OSPSInit(void){
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mflr r0
|
||||
stw r0, 4(r1)
|
||||
stwu r1, -8(r1)
|
||||
bl PPCMfhid2
|
||||
oris r3, r3, 0xa000
|
||||
bl PPCMthid2
|
||||
bl ICFlashInvalidate
|
||||
sync
|
||||
|
||||
li r3, 0
|
||||
mtspr 0x390, r3
|
||||
mtspr 0x391, r3
|
||||
mtspr 0x392, r3
|
||||
mtspr 0x393, r3
|
||||
mtspr 0x394, r3
|
||||
mtspr 0x395, r3
|
||||
mtspr 0x396, r3
|
||||
mtspr 0x397, r3
|
||||
|
||||
lwz r0, 0xc(r1)
|
||||
addi r1, r1, 8
|
||||
mtlr r0
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
vu32 __DIRegs[16] : 0xCC006000;
|
||||
#define DI_CONFIG_IDX 0x9
|
||||
#define DI_CONFIG_CONFIG_MASK 0xFF
|
||||
|
||||
u32 __OSGetDIConfig(void) {
|
||||
return (__DIRegs[DI_CONFIG_IDX] & DI_CONFIG_CONFIG_MASK);
|
||||
}
|
||||
|
||||
void OSRegisterVersion(const char* version) {
|
||||
OSReport("%s\n", version);
|
||||
}
|
228
src/dolphin/os/OSAlarm.c
Normal file
228
src/dolphin/os/OSAlarm.c
Normal file
@ -0,0 +1,228 @@
|
||||
#include "dolphin/os/OSAlarm.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
static BOOL OnReset(BOOL final);
|
||||
BOOL __DVDTestAlarm(OSAlarm* alarm);
|
||||
|
||||
static OSResetFunctionInfo ResetFunctionInfo = {
|
||||
OnReset,
|
||||
0xFFFFFFFF,
|
||||
};
|
||||
|
||||
static OSAlarmQueue AlarmQueue;
|
||||
|
||||
void OSInitAlarm(void) {
|
||||
if (__OSGetExceptionHandler(8) != DecrementerExceptionHandler) {
|
||||
AlarmQueue.head = AlarmQueue.tail = NULL;
|
||||
__OSSetExceptionHandler(8, DecrementerExceptionHandler);
|
||||
OSRegisterResetFunction(&ResetFunctionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void OSCreateAlarm(OSAlarm* alarm) {
|
||||
alarm->handler = NULL;
|
||||
alarm->tag = 0;
|
||||
}
|
||||
|
||||
static inline SetTimer(OSAlarm* alarm) {
|
||||
OSTime delta;
|
||||
|
||||
delta = alarm->fire_time - __OSGetSystemTime();
|
||||
if (delta < 0) {
|
||||
PPCMtdec(0);
|
||||
} else if (delta < 0x80000000) {
|
||||
PPCMtdec((u32)delta);
|
||||
} else {
|
||||
PPCMtdec(0x7fffffff);
|
||||
}
|
||||
}
|
||||
|
||||
static void InsertAlarm(OSAlarm* alarm, OSTime fire, OSAlarmHandler handler) {
|
||||
OSAlarm* next;
|
||||
OSAlarm* prev;
|
||||
|
||||
if (0 < alarm->period_time) {
|
||||
OSTime time = __OSGetSystemTime();
|
||||
|
||||
fire = alarm->start_time;
|
||||
if (alarm->start_time < time) {
|
||||
fire += alarm->period_time * ((time - alarm->start_time) / alarm->period_time + 1);
|
||||
}
|
||||
}
|
||||
|
||||
alarm->handler = handler;
|
||||
alarm->fire_time = fire;
|
||||
|
||||
for (next = AlarmQueue.head; next; next = next->link.next) {
|
||||
if (next->fire_time <= fire) {
|
||||
continue;
|
||||
}
|
||||
|
||||
alarm->link.prev = next->link.prev;
|
||||
next->link.prev = alarm;
|
||||
alarm->link.next = next;
|
||||
prev = alarm->link.prev;
|
||||
if (prev) {
|
||||
prev->link.next = alarm;
|
||||
} else {
|
||||
AlarmQueue.head = alarm;
|
||||
SetTimer(alarm);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
alarm->link.next = 0;
|
||||
prev = AlarmQueue.tail;
|
||||
AlarmQueue.tail = alarm;
|
||||
alarm->link.prev = prev;
|
||||
|
||||
if (prev) {
|
||||
prev->link.next = alarm;
|
||||
} else {
|
||||
AlarmQueue.head = AlarmQueue.tail = alarm;
|
||||
SetTimer(alarm);
|
||||
}
|
||||
}
|
||||
|
||||
void OSSetAlarm(OSAlarm* alarm, OSTime tick, OSAlarmHandler handler) {
|
||||
BOOL enabled;
|
||||
enabled = OSDisableInterrupts();
|
||||
alarm->period_time = 0;
|
||||
InsertAlarm(alarm, __OSGetSystemTime() + tick, handler);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSSetPeriodicAlarm(OSAlarm* alarm, OSTime start, OSTime period, OSAlarmHandler handler) {
|
||||
BOOL enabled;
|
||||
enabled = OSDisableInterrupts();
|
||||
alarm->period_time = period;
|
||||
alarm->start_time = __OSTimeToSystemTime(start);
|
||||
InsertAlarm(alarm, 0, handler);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSCancelAlarm(OSAlarm* alarm) {
|
||||
OSAlarm* next;
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
if (alarm->handler == 0) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return;
|
||||
}
|
||||
|
||||
next = alarm->link.next;
|
||||
if (next == 0) {
|
||||
AlarmQueue.tail = alarm->link.prev;
|
||||
} else {
|
||||
next->link.prev = alarm->link.prev;
|
||||
}
|
||||
if (alarm->link.prev) {
|
||||
alarm->link.prev->link.next = next;
|
||||
} else {
|
||||
AlarmQueue.head = next;
|
||||
if (next) {
|
||||
SetTimer(next);
|
||||
}
|
||||
}
|
||||
alarm->handler = 0;
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
static void DecrementerExceptionCallback(register __OSException exception,
|
||||
register OSContext* context) {
|
||||
OSAlarm* alarm;
|
||||
OSAlarm* next;
|
||||
OSAlarmHandler handler;
|
||||
OSTime time;
|
||||
OSContext exceptionContext;
|
||||
time = __OSGetSystemTime();
|
||||
alarm = AlarmQueue.head;
|
||||
if (alarm == 0) {
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
if (time < alarm->fire_time) {
|
||||
SetTimer(alarm);
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
next = alarm->link.next;
|
||||
AlarmQueue.head = next;
|
||||
if (next == 0) {
|
||||
AlarmQueue.tail = 0;
|
||||
} else {
|
||||
next->link.prev = 0;
|
||||
}
|
||||
|
||||
handler = alarm->handler;
|
||||
alarm->handler = 0;
|
||||
if (0 < alarm->period_time) {
|
||||
InsertAlarm(alarm, 0, handler);
|
||||
}
|
||||
|
||||
if (AlarmQueue.head) {
|
||||
SetTimer(AlarmQueue.head);
|
||||
}
|
||||
|
||||
OSDisableScheduler();
|
||||
OSClearContext(&exceptionContext);
|
||||
OSSetCurrentContext(&exceptionContext);
|
||||
handler(alarm, context);
|
||||
OSClearContext(&exceptionContext);
|
||||
OSSetCurrentContext(context);
|
||||
OSEnableScheduler();
|
||||
__OSReschedule();
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
static asm void DecrementerExceptionHandler(register __OSException exception,
|
||||
register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
stw r0, 0(context)
|
||||
stw r1, 4(context)
|
||||
stw r2, 8(context)
|
||||
stmw r6, 0x18(context)
|
||||
mfspr r0, 0x391
|
||||
stw r0, 0x1a8(context)
|
||||
mfspr r0, 0x392
|
||||
stw r0, 0x1ac(context)
|
||||
mfspr r0, 0x393
|
||||
stw r0, 0x1b0(context)
|
||||
mfspr r0, 0x394
|
||||
stw r0, 0x1b4(context)
|
||||
mfspr r0, 0x395
|
||||
stw r0, 0x1b8(context)
|
||||
mfspr r0, 0x396
|
||||
stw r0, 0x1bc(context)
|
||||
mfspr r0, 0x397
|
||||
stw r0, 0x1c0(context)
|
||||
stwu r1, -8(r1)
|
||||
b DecrementerExceptionCallback
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static BOOL OnReset(BOOL final) {
|
||||
OSAlarm* alarm;
|
||||
OSAlarm* next;
|
||||
|
||||
if (final != FALSE) {
|
||||
alarm = AlarmQueue.head;
|
||||
next = (alarm) ? alarm->link.next : NULL;
|
||||
|
||||
while (alarm != NULL) {
|
||||
if (__DVDTestAlarm(alarm) == FALSE) {
|
||||
OSCancelAlarm(alarm);
|
||||
}
|
||||
|
||||
alarm = next;
|
||||
next = (alarm) ? alarm->link.next : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
127
src/dolphin/os/OSAlloc.c
Normal file
127
src/dolphin/os/OSAlloc.c
Normal file
@ -0,0 +1,127 @@
|
||||
#include "dolphin/os/OSAlloc.h"
|
||||
|
||||
static OSHeapCell* DLInsert(OSHeapCell* list, OSHeapCell* child) {
|
||||
OSHeapCell* prev = NULL;
|
||||
OSHeapCell* next = list;
|
||||
|
||||
for (; next != NULL; prev = next, next = next->next) {
|
||||
if ((char*)child <= (char*)next) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
child->next = next;
|
||||
child->prev = prev;
|
||||
|
||||
if (next != NULL) {
|
||||
next->prev = child;
|
||||
|
||||
if ((char*)child + child->size == (char*)next) {
|
||||
child->size += next->size;
|
||||
next = next->next;
|
||||
child->next = next;
|
||||
if (next != NULL) {
|
||||
next->prev = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prev != NULL) {
|
||||
prev->next = child;
|
||||
|
||||
if ((char*)prev + prev->size == (char*)child) {
|
||||
prev->size += child->size;
|
||||
prev->next = next;
|
||||
if (next != NULL) {
|
||||
next->prev = prev;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
} else {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
inline OSHeapCell* DLExtract(OSHeapCell* list, OSHeapCell* child) {
|
||||
if (child->next != NULL) {
|
||||
child->next->prev = child->prev;
|
||||
}
|
||||
|
||||
if (child->prev == NULL) {
|
||||
return child->next;
|
||||
}
|
||||
|
||||
child->prev->next = child->next;
|
||||
return list;
|
||||
}
|
||||
|
||||
static OSHeapDescriptor* HeapArray;
|
||||
|
||||
void OSFreeToHeap(OSHeapHandle handle, void* ptr) {
|
||||
OSHeapDescriptor* hd = &HeapArray[handle];
|
||||
OSHeapCell* cell = (OSHeapCell*)((char*)ptr - sizeof(OSHeapCell));
|
||||
hd->usedList = DLExtract(hd->usedList, cell);
|
||||
hd->freeList = DLInsert(hd->freeList, cell);
|
||||
}
|
||||
|
||||
volatile s32 __OSCurrHeap = -1;
|
||||
|
||||
s32 OSSetCurrentHeap(OSHeapHandle handle) {
|
||||
s32 old = __OSCurrHeap;
|
||||
__OSCurrHeap = handle;
|
||||
return old;
|
||||
}
|
||||
|
||||
static s32 NumHeaps;
|
||||
|
||||
static void* ArenaStart;
|
||||
|
||||
static void* ArenaEnd;
|
||||
|
||||
void* OSInitAlloc(void* lo, void* hi, s32 maxHeaps) {
|
||||
u32 totalSize = maxHeaps * sizeof(OSHeapDescriptor);
|
||||
int i;
|
||||
|
||||
HeapArray = lo;
|
||||
NumHeaps = maxHeaps;
|
||||
|
||||
for (i = 0; i < NumHeaps; i++) {
|
||||
OSHeapDescriptor* hd = &HeapArray[i];
|
||||
hd->size = -1;
|
||||
|
||||
hd->freeList = hd->usedList = NULL;
|
||||
}
|
||||
|
||||
__OSCurrHeap = -1;
|
||||
|
||||
lo = (u8*)HeapArray + totalSize;
|
||||
lo = OSRoundUpPtr(lo, 0x20);
|
||||
|
||||
ArenaStart = lo;
|
||||
ArenaEnd = OSRoundDownPtr(hi, 0x20);
|
||||
|
||||
return ArenaStart;
|
||||
}
|
||||
|
||||
OSHeapHandle OSCreateHeap(void* start, void* end) {
|
||||
int i;
|
||||
OSHeapCell* cell = OSRoundUpPtr(start, 0x20);
|
||||
end = OSRoundDownPtr(end, 0x20);
|
||||
|
||||
for (i = 0; i < NumHeaps; i++) {
|
||||
OSHeapDescriptor* hd = &HeapArray[i];
|
||||
|
||||
if (hd->size < 0) {
|
||||
hd->size = (u8*)end - (u8*)cell;
|
||||
cell->prev = NULL;
|
||||
cell->next = NULL;
|
||||
cell->size = hd->size;
|
||||
hd->freeList = cell;
|
||||
hd->usedList = NULL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
31
src/dolphin/os/OSArena.c
Normal file
31
src/dolphin/os/OSArena.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include "dolphin/os/OSArena.h"
|
||||
#include "dolphin/os/OSAlloc.h"
|
||||
|
||||
static void* __OSArenaHi;
|
||||
|
||||
void* OSGetArenaHi(void) {
|
||||
return __OSArenaHi;
|
||||
}
|
||||
|
||||
static void* __OSArenaLo = (void*)0xFFFFFFFF;
|
||||
|
||||
void* OSGetArenaLo(void) {
|
||||
return __OSArenaLo;
|
||||
}
|
||||
|
||||
void OSSetArenaHi(void* hi) {
|
||||
__OSArenaHi = hi;
|
||||
}
|
||||
|
||||
void OSSetArenaLo(void* lo) {
|
||||
__OSArenaLo = lo;
|
||||
}
|
||||
|
||||
void* OSAllocFromArenaLo(u32 size, s32 alignment) {
|
||||
u8* blk_start = OSRoundUpPtr(__OSArenaLo, alignment);
|
||||
u8* blk_end = blk_start + size;
|
||||
blk_end = OSRoundUpPtr(blk_end, alignment);
|
||||
|
||||
__OSArenaLo = blk_end;
|
||||
return blk_start;
|
||||
}
|
105
src/dolphin/os/OSAudioSystem.c
Normal file
105
src/dolphin/os/OSAudioSystem.c
Normal file
@ -0,0 +1,105 @@
|
||||
#include "dolphin/os/OSAudioSystem.h"
|
||||
#include "dolphin/dsp.h"
|
||||
#include "string.h"
|
||||
|
||||
static u8 DSPInitCode[128] = {
|
||||
0x02, 0x9F, 0x00, 0x10, 0x02, 0x9F, 0x00, 0x33, 0x02, 0x9F, 0x00, 0x34, 0x02, 0x9F, 0x00, 0x35,
|
||||
0x02, 0x9F, 0x00, 0x36, 0x02, 0x9F, 0x00, 0x37, 0x02, 0x9F, 0x00, 0x38, 0x02, 0x9F, 0x00, 0x39,
|
||||
0x12, 0x06, 0x12, 0x03, 0x12, 0x04, 0x12, 0x05, 0x00, 0x80, 0x80, 0x00, 0x00, 0x88, 0xFF, 0xFF,
|
||||
0x00, 0x84, 0x10, 0x00, 0x00, 0x64, 0x00, 0x1D, 0x02, 0x18, 0x00, 0x00, 0x81, 0x00, 0x1C, 0x1E,
|
||||
0x00, 0x44, 0x1B, 0x1E, 0x00, 0x84, 0x08, 0x00, 0x00, 0x64, 0x00, 0x27, 0x19, 0x1E, 0x00, 0x00,
|
||||
0x00, 0xDE, 0xFF, 0xFC, 0x02, 0xA0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x28, 0x16, 0xFC, 0x00, 0x54,
|
||||
0x16, 0xFD, 0x43, 0x48, 0x00, 0x21, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF,
|
||||
0x02, 0xFF, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
#define __DSPWorkBuffer (void*)0x81000000
|
||||
|
||||
void __OSInitAudioSystem(void) {
|
||||
u32 r28;
|
||||
u16 r3;
|
||||
|
||||
u32 padding;
|
||||
|
||||
memcpy((void*)((u8*)OSGetArenaHi() - 128), __DSPWorkBuffer, 128);
|
||||
memcpy(__DSPWorkBuffer, (void*)DSPInitCode, 128);
|
||||
|
||||
DCFlushRange(__DSPWorkBuffer, 128);
|
||||
|
||||
__DSPRegs[9] = 0x43;
|
||||
__DSPRegs[5] = 0x8AC;
|
||||
__DSPRegs[5] |= 1;
|
||||
while (__DSPRegs[5] & 1)
|
||||
;
|
||||
__DSPRegs[0] = 0;
|
||||
while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000)
|
||||
;
|
||||
*(u32*)&__DSPRegs[16] = 0x1000000;
|
||||
*(u32*)&__DSPRegs[18] = 0;
|
||||
*(u32*)&__DSPRegs[20] = 0x20;
|
||||
|
||||
r3 = __DSPRegs[5];
|
||||
while (!(r3 & 0x20))
|
||||
r3 = __DSPRegs[5];
|
||||
__DSPRegs[5] = r3;
|
||||
|
||||
r28 = OSGetTick();
|
||||
while ((s32)(OSGetTick() - r28) < 0x892)
|
||||
;
|
||||
|
||||
*(u32*)&__DSPRegs[16] = 0x1000000;
|
||||
*(u32*)&__DSPRegs[18] = 0;
|
||||
*(u32*)&__DSPRegs[20] = 0x20;
|
||||
|
||||
r3 = __DSPRegs[5];
|
||||
while (!(r3 & 0x20))
|
||||
r3 = __DSPRegs[5];
|
||||
__DSPRegs[5] = r3;
|
||||
|
||||
__DSPRegs[5] &= ~0x800;
|
||||
while ((__DSPRegs[5]) & 0x400)
|
||||
;
|
||||
__DSPRegs[5] &= ~4;
|
||||
|
||||
r3 = __DSPRegs[2];
|
||||
|
||||
while (!(r3 & 0x8000))
|
||||
r3 = __DSPRegs[2];
|
||||
|
||||
(void)__DSPRegs[3];
|
||||
r3 != 42069;
|
||||
__DSPRegs[5] |= 4;
|
||||
__DSPRegs[5] = 0x8AC;
|
||||
__DSPRegs[5] |= 1;
|
||||
while (__DSPRegs[5] & 1)
|
||||
;
|
||||
memcpy(__DSPWorkBuffer, (void*)((u8*)OSGetArenaHi() - 128), 128);
|
||||
}
|
||||
|
||||
void __OSStopAudioSystem(void) {
|
||||
u32 r28;
|
||||
|
||||
#define waitUntil(load, mask) \
|
||||
r28 = (load); \
|
||||
while (r28 & (mask)) { \
|
||||
r28 = (load); \
|
||||
}
|
||||
|
||||
__DSPRegs[5] = 0x804;
|
||||
r28 = __DSPRegs[27];
|
||||
__DSPRegs[27] = r28 & ~0x8000;
|
||||
waitUntil(__DSPRegs[5], 0x400);
|
||||
waitUntil(__DSPRegs[5], 0x200);
|
||||
__DSPRegs[5] = 0x8ac;
|
||||
__DSPRegs[0] = 0;
|
||||
|
||||
while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000)
|
||||
;
|
||||
r28 = OSGetTick();
|
||||
while ((s32)(OSGetTick() - r28) < 0x2c)
|
||||
;
|
||||
__DSPRegs[5] |= 1;
|
||||
waitUntil(__DSPRegs[5], 0x001);
|
||||
|
||||
#undef waitUntil
|
||||
}
|
432
src/dolphin/os/OSCache.c
Normal file
432
src/dolphin/os/OSCache.c
Normal file
@ -0,0 +1,432 @@
|
||||
#include "dolphin/os/OSCache.h"
|
||||
#include "dolphin/base/PPCArch.h"
|
||||
// #include "dolphin/db.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
static asm void DCEnable(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
sync
|
||||
mfspr r3, 0x3F0
|
||||
ori r3, r3, 0x4000
|
||||
mtspr 0x3F0, r3
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void DCInvalidateRange(register void* start, register u32 nBytes) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
|
||||
clrlwi r5, start, 0x1B
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 0x1F
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
do_invalidate:
|
||||
dcbi 0, start
|
||||
addi start, start, 0x20
|
||||
bdnz do_invalidate
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void DCFlushRange(register void* start, register u32 nBytes) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
|
||||
clrlwi r5, start, 0x1B
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 0x1F
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
do_flush:
|
||||
dcbf 0, start
|
||||
addi start, start, 0x20
|
||||
bdnz do_flush
|
||||
sc
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void DCStoreRange(register void* start, register u32 nBytes) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
|
||||
clrlwi r5, start, 0x1B
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 0x1F
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
do_store:
|
||||
dcbst 0, start
|
||||
addi start, start, 0x20
|
||||
bdnz do_store
|
||||
sc
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void DCFlushRangeNoSync(register void* start, register u32 nBytes) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
|
||||
clrlwi r5, start, 0x1B
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 0x1F
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
do_flush:
|
||||
dcbf 0, start
|
||||
addi start, start, 0x20
|
||||
bdnz do_flush
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void DCStoreRangeNoSync(register void* start, register u32 nBytes) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
|
||||
clrlwi r5, start, 0x1B
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 0x1F
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
do_store:
|
||||
dcbst 0, start
|
||||
addi start, start, 0x20
|
||||
bdnz do_store
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void DCZeroRange(register void* start, register u32 nBytes) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
|
||||
clrlwi r5, start, 0x1B
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 0x1F
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
do_zero:
|
||||
dcbz 0, start
|
||||
addi start, start, 0x20
|
||||
bdnz do_zero
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void ICInvalidateRange(register void* start, register u32 nBytes) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
|
||||
clrlwi r5, start, 0x1B
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 0x1F
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
do_invalidate:
|
||||
icbi 0, start
|
||||
addi start, start, 0x20
|
||||
bdnz do_invalidate
|
||||
|
||||
sync
|
||||
isync
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void ICFlashInvalidate(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mfspr r3, 0x3F0
|
||||
ori r3, r3, 0x800
|
||||
mtspr 0x3F0, r3
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static asm void ICEnable(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
isync
|
||||
mfspr r3, 0x3F0
|
||||
ori r3, r3, 0x8000
|
||||
mtspr 0x3F0, r3
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void __LCEnable(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mfmsr r5
|
||||
ori r5, r5, 0x1000
|
||||
mtmsr r5
|
||||
|
||||
lis r3, 0x8000
|
||||
li r4, 0x400
|
||||
mtctr r4
|
||||
|
||||
do_store:
|
||||
dcbt 0, r3
|
||||
dcbst 0, r3
|
||||
addi r3, r3, 0x20
|
||||
bdnz do_store
|
||||
|
||||
mfspr r4, 0x398
|
||||
oris r4, r4, 0x100F
|
||||
mtspr 0x398, r4
|
||||
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
lis r3, 0xE000
|
||||
ori r3, r3, 0x0002
|
||||
mtdbatl 3, r3
|
||||
ori r3, r3, 0x1FE
|
||||
mtdbatu 3, r3
|
||||
isync
|
||||
|
||||
lis r3, 0xE000
|
||||
li r6, 0x200
|
||||
mtctr r6
|
||||
li r6, 0
|
||||
do_load:
|
||||
dcbz_l r6, r3
|
||||
addi r3, r3, 0x0020
|
||||
bdnz do_load
|
||||
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void LCEnable(void) {
|
||||
BOOL interrupt = OSDisableInterrupts();
|
||||
__LCEnable();
|
||||
OSRestoreInterrupts(interrupt);
|
||||
}
|
||||
|
||||
asm void LCDisable(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
lis r3, 0xE000
|
||||
li r4, 0x200
|
||||
mtctr r4
|
||||
do_invalidate:
|
||||
dcbi 0, r3
|
||||
addi r3, r3, 0x20
|
||||
bdnz do_invalidate
|
||||
|
||||
mfspr r4, 0x398
|
||||
rlwinm r4, r4, 0, 4, 2
|
||||
mtspr 0x398, r4
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static asm void LCStoreBlocks(register void* destAddr, register void* srcAddr,
|
||||
register u32 blockNum){
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
rlwinm r6, blockNum, 0x1E, 0x1B, 0x1F
|
||||
clrlwi destAddr, destAddr, 4
|
||||
or r6, r6, destAddr
|
||||
mtspr 0x39A, r6
|
||||
rlwinm r6, blockNum, 2, 0x1C, 0x1D
|
||||
or r6, r6, srcAddr
|
||||
ori r6, r6, 2
|
||||
mtspr 0x39B, r6
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
} /* 8033B838-8033B8E4 336178 00AC+00 0/0 0/0 3/3 .text LCStoreData */
|
||||
u32 LCStoreData(void* destAddr, void* srcAddr, u32 nBytes) {
|
||||
u32 blocks = (nBytes + 31) / 32;
|
||||
u32 ret = (blocks + 127) / 128;
|
||||
|
||||
while (blocks > 0) {
|
||||
if (blocks < 128) {
|
||||
LCStoreBlocks(destAddr, srcAddr, blocks);
|
||||
blocks = 0;
|
||||
} else {
|
||||
LCStoreBlocks(destAddr, srcAddr, 0);
|
||||
blocks -= 128;
|
||||
|
||||
destAddr = (char*)destAddr + 0x1000;
|
||||
srcAddr = (char*)srcAddr + 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
asm void LCQueueWait(register u32 len) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mfspr r4, 0x398
|
||||
rlwinm r4, r4, 8, 28, 31
|
||||
cmpw r4, len
|
||||
bgt LCQueueWait
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static void L2Disable(void) {
|
||||
__sync();
|
||||
PPCMtl2cr(PPCMfl2cr() & ~0x80000000);
|
||||
__sync();
|
||||
}
|
||||
|
||||
void L2GlobalInvalidate(void) {
|
||||
L2Disable();
|
||||
PPCMtl2cr(PPCMfl2cr() | 0x00200000);
|
||||
while (PPCMfl2cr() & 0x00000001u)
|
||||
;
|
||||
PPCMtl2cr(PPCMfl2cr() & ~0x00200000);
|
||||
while (PPCMfl2cr() & 0x00000001u) {
|
||||
DBPrintf(">>> L2 INVALIDATE : SHOULD NEVER HAPPEN\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DMAErrorHandler(u16 error, OSContext* context, ...) {
|
||||
u32 hid2 = PPCMfhid2();
|
||||
|
||||
OSReport("Machine check received\n");
|
||||
OSReport("HID2 = 0x%x SRR1 = 0x%x\n", hid2, context->srr1);
|
||||
if (!(hid2 & (HID2_DCHERR | HID2_DNCERR | HID2_DCMERR | HID2_DQOERR)) ||
|
||||
!(context->srr1 & SRR1_DMA_BIT)) {
|
||||
OSReport("Machine check was not DMA/locked cache related\n");
|
||||
OSDumpContext(context);
|
||||
PPCHalt();
|
||||
}
|
||||
|
||||
OSReport("DMAErrorHandler(): An error occurred while processing DMA.\n");
|
||||
OSReport("The following errors have been detected and cleared :\n");
|
||||
|
||||
if (hid2 & HID2_DCHERR) {
|
||||
OSReport("\t- Requested a locked cache tag that was already in the cache\n");
|
||||
}
|
||||
|
||||
if (hid2 & HID2_DNCERR) {
|
||||
OSReport("\t- DMA attempted to access normal cache\n");
|
||||
}
|
||||
|
||||
if (hid2 & HID2_DCMERR) {
|
||||
OSReport("\t- DMA missed in data cache\n");
|
||||
}
|
||||
|
||||
if (hid2 & HID2_DQOERR) {
|
||||
OSReport("\t- DMA queue overflowed\n");
|
||||
}
|
||||
|
||||
// write hid2 back to clear the error bits
|
||||
PPCMthid2(hid2);
|
||||
}
|
||||
|
||||
static void L2Init(void) {
|
||||
u32 oldMSR;
|
||||
oldMSR = PPCMfmsr();
|
||||
__sync();
|
||||
PPCMtmsr(MSR_IR | MSR_DR);
|
||||
__sync();
|
||||
L2Disable();
|
||||
L2GlobalInvalidate();
|
||||
PPCMtmsr(oldMSR);
|
||||
}
|
||||
|
||||
void L2Enable(void) {
|
||||
PPCMtl2cr((PPCMfl2cr() | L2CR_L2E) & ~L2CR_L2I);
|
||||
}
|
||||
|
||||
void __OSCacheInit() {
|
||||
if (!(PPCMfhid0() & HID0_ICE)) {
|
||||
ICEnable();
|
||||
DBPrintf("L1 i-caches initialized\n");
|
||||
}
|
||||
if (!(PPCMfhid0() & HID0_DCE)) {
|
||||
DCEnable();
|
||||
DBPrintf("L1 d-caches initialized\n");
|
||||
}
|
||||
|
||||
if (!(PPCMfl2cr() & L2CR_L2E)) {
|
||||
L2Init();
|
||||
L2Enable();
|
||||
DBPrintf("L2 cache initialized\n");
|
||||
}
|
||||
|
||||
OSSetErrorHandler(OS_ERROR_MACHINE_CHECK, DMAErrorHandler);
|
||||
DBPrintf("Locked cache machine check handler installed\n");
|
||||
}
|
611
src/dolphin/os/OSContext.c
Normal file
611
src/dolphin/os/OSContext.c
Normal file
@ -0,0 +1,611 @@
|
||||
#include "dolphin/os/OSContext.h"
|
||||
// #include "dolphin/db.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
volatile OSContext* __OSCurrentContext : (OS_BASE_CACHED | 0x00D4);
|
||||
volatile OSContext* __OSFPUContext : (OS_BASE_CACHED | 0x00D8);
|
||||
|
||||
asm void __OSLoadFPUContext(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
lhz r5, 0x1A2(r4)
|
||||
clrlwi. r5, r5, 0x1f
|
||||
beq exit
|
||||
|
||||
lfd f0, 0x190(r4)
|
||||
mtfsf 0xFF, f0
|
||||
mfspr r5, 0x398
|
||||
rlwinm. r5, r5, 3, 0x1F, 0x1F
|
||||
beq load_fprs
|
||||
|
||||
psq_l f0, 0x1C8(r4), 0, 0
|
||||
psq_l f1, 0x1D0(r4), 0, 0
|
||||
psq_l f2, 0x1D8(r4), 0, 0
|
||||
psq_l f3, 0x1E0(r4), 0, 0
|
||||
psq_l f4, 0x1E8(r4), 0, 0
|
||||
psq_l f5, 0x1F0(r4), 0, 0
|
||||
psq_l f6, 0x1F8(r4), 0, 0
|
||||
psq_l f7, 0x200(r4), 0, 0
|
||||
psq_l f8, 0x208(r4), 0, 0
|
||||
psq_l f9, 0x210(r4), 0, 0
|
||||
psq_l f10, 0x218(r4), 0, 0
|
||||
psq_l f11, 0x220(r4), 0, 0
|
||||
psq_l f12, 0x228(r4), 0, 0
|
||||
psq_l f13, 0x230(r4), 0, 0
|
||||
psq_l f14, 0x238(r4), 0, 0
|
||||
psq_l f15, 0x240(r4), 0, 0
|
||||
psq_l f16, 0x248(r4), 0, 0
|
||||
psq_l f17, 0x250(r4), 0, 0
|
||||
psq_l f18, 0x258(r4), 0, 0
|
||||
psq_l f19, 0x260(r4), 0, 0
|
||||
psq_l f20, 0x268(r4), 0, 0
|
||||
psq_l f21, 0x270(r4), 0, 0
|
||||
psq_l f22, 0x278(r4), 0, 0
|
||||
psq_l f23, 0x280(r4), 0, 0
|
||||
psq_l f24, 0x288(r4), 0, 0
|
||||
psq_l f25, 0x290(r4), 0, 0
|
||||
psq_l f26, 0x298(r4), 0, 0
|
||||
psq_l f27, 0x2A0(r4), 0, 0
|
||||
psq_l f28, 0x2A8(r4), 0, 0
|
||||
psq_l f29, 0x2B0(r4), 0, 0
|
||||
psq_l f30, 0x2B8(r4), 0, 0
|
||||
psq_l f31, 0x2C0(r4), 0, 0
|
||||
|
||||
load_fprs:
|
||||
lfd f0, 0x90(r4)
|
||||
lfd f1, 0x98(r4)
|
||||
lfd f2, 0xA0(r4)
|
||||
lfd f3, 0xA8(r4)
|
||||
lfd f4, 0xB0(r4)
|
||||
lfd f5, 0xB8(r4)
|
||||
lfd f6, 0xC0(r4)
|
||||
lfd f7, 0xC8(r4)
|
||||
lfd f8, 0xD0(r4)
|
||||
lfd f9, 0xD8(r4)
|
||||
lfd f10, 0xE0(r4)
|
||||
lfd f11, 0xE8(r4)
|
||||
lfd f12, 0xF0(r4)
|
||||
lfd f13, 0xF8(r4)
|
||||
lfd f14, 0x100(r4)
|
||||
lfd f15, 0x108(r4)
|
||||
lfd f16, 0x110(r4)
|
||||
lfd f17, 0x118(r4)
|
||||
lfd f18, 0x120(r4)
|
||||
lfd f19, 0x128(r4)
|
||||
lfd f20, 0x130(r4)
|
||||
lfd f21, 0x138(r4)
|
||||
lfd f22, 0x140(r4)
|
||||
lfd f23, 0x148(r4)
|
||||
lfd f24, 0x150(r4)
|
||||
lfd f25, 0x158(r4)
|
||||
lfd f26, 0x160(r4)
|
||||
lfd f27, 0x168(r4)
|
||||
lfd f28, 0x170(r4)
|
||||
lfd f29, 0x178(r4)
|
||||
lfd f30, 0x180(r4)
|
||||
lfd f31, 0x188(r4)
|
||||
|
||||
exit:
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void __OSSaveFPUContext(s32 unused0, s32 unused1, register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
lhz r3, 0x1A2(context)
|
||||
ori r3, r3, 1
|
||||
sth r3, 0x1A2(context)
|
||||
|
||||
stfd f0, 0x90(context)
|
||||
stfd f1, 0x98(context)
|
||||
stfd f2, 0xa0(context)
|
||||
stfd f3, 0xa8(context)
|
||||
stfd f4, 0xb0(context)
|
||||
stfd f5, 0xb8(context)
|
||||
stfd f6, 0xc0(context)
|
||||
stfd f7, 0xc8(context)
|
||||
stfd f8, 0xd0(context)
|
||||
stfd f9, 0xd8(context)
|
||||
stfd f10, 0xe0(context)
|
||||
stfd f11, 0xe8(context)
|
||||
stfd f12, 0xf0(context)
|
||||
stfd f13, 0xf8(context)
|
||||
stfd f14, 0x100(context)
|
||||
stfd f15, 0x108(context)
|
||||
stfd f16, 0x110(context)
|
||||
stfd f17, 0x118(context)
|
||||
stfd f18, 0x120(context)
|
||||
stfd f19, 0x128(context)
|
||||
stfd f20, 0x130(context)
|
||||
stfd f21, 0x138(context)
|
||||
stfd f22, 0x140(context)
|
||||
stfd f23, 0x148(context)
|
||||
stfd f24, 0x150(context)
|
||||
stfd f25, 0x158(context)
|
||||
stfd f26, 0x160(context)
|
||||
stfd f27, 0x168(context)
|
||||
stfd f28, 0x170(context)
|
||||
stfd f29, 0x178(context)
|
||||
stfd f30, 0x180(context)
|
||||
stfd f31, 0x188(context)
|
||||
|
||||
mffs f0
|
||||
stfd f0, 0x190(context)
|
||||
lfd f0, 0x90(context)
|
||||
mfspr r3, 0x398
|
||||
rlwinm. r3, r3, 3, 0x1f, 0x1f
|
||||
beq exit
|
||||
|
||||
psq_st f0, 456(context), 0, 0
|
||||
psq_st f1, 464(context), 0, 0
|
||||
psq_st f2, 472(context), 0, 0
|
||||
psq_st f3, 480(context), 0, 0
|
||||
psq_st f4, 488(context), 0, 0
|
||||
psq_st f5, 496(context), 0, 0
|
||||
psq_st f6, 504(context), 0, 0
|
||||
psq_st f7, 512(context), 0, 0
|
||||
psq_st f8, 520(context), 0, 0
|
||||
psq_st f9, 528(context), 0, 0
|
||||
psq_st f10, 536(context), 0, 0
|
||||
psq_st f11, 544(context), 0, 0
|
||||
psq_st f12, 552(context), 0, 0
|
||||
psq_st f13, 560(context), 0, 0
|
||||
psq_st f14, 568(context), 0, 0
|
||||
psq_st f15, 576(context), 0, 0
|
||||
psq_st f16, 584(context), 0, 0
|
||||
psq_st f17, 592(context), 0, 0
|
||||
psq_st f18, 600(context), 0, 0
|
||||
psq_st f19, 608(context), 0, 0
|
||||
psq_st f20, 616(context), 0, 0
|
||||
psq_st f21, 624(context), 0, 0
|
||||
psq_st f22, 632(context), 0, 0
|
||||
psq_st f23, 640(context), 0, 0
|
||||
psq_st f24, 648(context), 0, 0
|
||||
psq_st f25, 656(context), 0, 0
|
||||
psq_st f26, 664(context), 0, 0
|
||||
psq_st f27, 672(context), 0, 0
|
||||
psq_st f28, 680(context), 0, 0
|
||||
psq_st f29, 688(context), 0, 0
|
||||
psq_st f30, 696(context), 0, 0
|
||||
psq_st f31, 704(context), 0, 0
|
||||
|
||||
exit:
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void OSSaveFPUContext(register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
addi r5, context, 0
|
||||
b __OSSaveFPUContext
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void OSSetCurrentContext(register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
lis r4, OS_CURRENT_CONTEXT@ha
|
||||
stw context, OS_CURRENT_CONTEXT@l(r4)
|
||||
clrlwi r5, context, 2
|
||||
stw r5, 0xc0(r4)
|
||||
lwz r5, 0xd8(r4)
|
||||
cmpw r5, context
|
||||
bne lbl_800EE9AC
|
||||
lwz r6, 0x19c(context)
|
||||
ori r6, r6, 0x2000
|
||||
stw r6, 0x19c(context)
|
||||
mfmsr r6
|
||||
ori r6, r6, 2
|
||||
mtmsr r6
|
||||
blr
|
||||
|
||||
lbl_800EE9AC:
|
||||
lwz r6, 0x19c(context)
|
||||
rlwinm r6, r6, 0, 0x13, 0x11
|
||||
stw r6, 0x19c(context)
|
||||
mfmsr r6
|
||||
rlwinm r6, r6, 0, 0x13, 0x11
|
||||
ori r6, r6, 2
|
||||
mtmsr r6
|
||||
isync
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
OSContext* OSGetCurrentContext(void) {
|
||||
return OS_CURRENT_CONTEXT;
|
||||
}
|
||||
|
||||
asm u32 OSSaveContext(register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
stmw r13, 0x34(context)
|
||||
|
||||
mfspr r0, GQR1
|
||||
stw r0, 0x1a8(context)
|
||||
mfspr r0, GQR2
|
||||
stw r0, 0x1ac(context)
|
||||
mfspr r0, GQR3
|
||||
stw r0, 0x1b0(context)
|
||||
mfspr r0, GQR4
|
||||
stw r0, 0x1b4(context)
|
||||
mfspr r0, GQR5
|
||||
stw r0, 0x1b8(context)
|
||||
mfspr r0, GQR6
|
||||
stw r0, 0x1bc(context)
|
||||
mfspr r0, GQR7
|
||||
stw r0, 0x1c0(context)
|
||||
|
||||
mfcr r0
|
||||
stw r0, 0x80(context)
|
||||
mflr r0
|
||||
stw r0, 0x84(context)
|
||||
stw r0, 0x198(context)
|
||||
mfmsr r0
|
||||
stw r0, 0x19c(context)
|
||||
mfctr r0
|
||||
stw r0, 0x88(context)
|
||||
mfxer r0
|
||||
stw r0, 0x8c(context)
|
||||
|
||||
stw r1, 4(context)
|
||||
stw r2, 8(context)
|
||||
|
||||
li r0, 1
|
||||
stw r0, 0xc(context)
|
||||
|
||||
li r3, 0
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm void OSLoadContext(register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
lis r4, OSDisableInterrupts@ha
|
||||
lwz r6, 0x198(context)
|
||||
addi r5, r4, OSDisableInterrupts@l
|
||||
cmplw r6, r5
|
||||
ble srr0_not_in_disableintr
|
||||
lis r4, __RAS_OSDisableInterrupts_end@ha
|
||||
addi r0, r4, __RAS_OSDisableInterrupts_end@l
|
||||
cmplw r6, r0
|
||||
bge srr0_not_in_disableintr
|
||||
stw r5, 0x198(context)
|
||||
|
||||
srr0_not_in_disableintr:
|
||||
lwz r0, 0(context)
|
||||
lwz r1, 4(context)
|
||||
lwz r2, 8(context)
|
||||
lhz r4, 0x1a2(context)
|
||||
rlwinm. r5, r4, 0, 0x1e, 0x1e
|
||||
beq load_saved_gprs
|
||||
rlwinm r4, r4, 0, 0x1f, 0x1d
|
||||
sth r4, 0x1a2(context)
|
||||
lmw r5, 0x14(context)
|
||||
b load_special_regs
|
||||
|
||||
load_saved_gprs:
|
||||
lmw r13, 0x34(context)
|
||||
|
||||
load_special_regs:
|
||||
lwz r4, 0x1a8(context)
|
||||
mtspr 0x391, r4
|
||||
lwz r4, 0x1ac(context)
|
||||
mtspr 0x392, r4
|
||||
lwz r4, 0x1b0(context)
|
||||
mtspr 0x393, r4
|
||||
lwz r4, 0x1b4(context)
|
||||
mtspr 0x394, r4
|
||||
lwz r4, 0x1b8(context)
|
||||
mtspr 0x395, r4
|
||||
lwz r4, 0x1bc(context)
|
||||
mtspr 0x396, r4
|
||||
lwz r4, 0x1c0(context)
|
||||
mtspr 0x397, r4
|
||||
lwz r4, 0x80(context)
|
||||
mtcrf 0xff, r4
|
||||
lwz r4, 0x84(context)
|
||||
mtlr r4
|
||||
lwz r4, 0x88(context)
|
||||
mtctr r4
|
||||
lwz r4, 0x8c(context)
|
||||
mtxer r4
|
||||
mfmsr r4
|
||||
rlwinm r4, r4, 0, 0x11, 0xf
|
||||
rlwinm r4, r4, 0, 0x1f, 0x1d
|
||||
mtmsr r4
|
||||
lwz r4, 0x198(context)
|
||||
mtspr 0x1a, r4
|
||||
lwz r4, 0x19c(context)
|
||||
mtspr 0x1b, r4
|
||||
lwz r4, 0x10(context)
|
||||
lwz context, 0xc(context)
|
||||
rfi
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm u8* OSGetStackPointer(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mr r3, r1
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void OSClearContext(OSContext* context) {
|
||||
context->mode = 0;
|
||||
context->state = 0;
|
||||
|
||||
if (context == OS_CURRENT_FPU_CONTEXT) {
|
||||
OS_CURRENT_FPU_CONTEXT = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
asm void OSInitContext(register OSContext* context, register u32 srr0, register u32 stack) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
stw srr0, 0x198(context)
|
||||
stw stack, 4(context)
|
||||
li r11, 0
|
||||
ori r11, r11, 0x9032
|
||||
stw r11, 0x19c(context)
|
||||
li r0, 0
|
||||
stw r0, 0x80(context)
|
||||
stw r0, 0x8c(context)
|
||||
stw r2, 8(context)
|
||||
stw r13, 0x34(context)
|
||||
stw r0, 0xc(context)
|
||||
stw r0, 0x10(context)
|
||||
stw r0, 0x14(context)
|
||||
stw r0, 0x18(context)
|
||||
stw r0, 0x1c(context)
|
||||
stw r0, 0x20(context)
|
||||
stw r0, 0x24(context)
|
||||
stw r0, 0x28(context)
|
||||
stw r0, 0x2c(context)
|
||||
stw r0, 0x30(context)
|
||||
stw r0, 0x38(context)
|
||||
stw r0, 0x3c(context)
|
||||
stw r0, 0x40(context)
|
||||
stw r0, 0x44(context)
|
||||
stw r0, 0x48(context)
|
||||
stw r0, 0x4c(context)
|
||||
stw r0, 0x50(context)
|
||||
stw r0, 0x54(context)
|
||||
stw r0, 0x58(context)
|
||||
stw r0, 0x5c(context)
|
||||
stw r0, 0x60(context)
|
||||
stw r0, 0x64(context)
|
||||
stw r0, 0x68(context)
|
||||
stw r0, 0x6c(context)
|
||||
stw r0, 0x70(context)
|
||||
stw r0, 0x74(context)
|
||||
stw r0, 0x78(context)
|
||||
stw r0, 0x7c(context)
|
||||
stw r0, 0x1a4(context)
|
||||
stw r0, 0x1a8(context)
|
||||
stw r0, 0x1ac(context)
|
||||
stw r0, 0x1b0(context)
|
||||
stw r0, 0x1b4(context)
|
||||
stw r0, 0x1b8(context)
|
||||
stw r0, 0x1bc(context)
|
||||
stw r0, 0x1c0(context)
|
||||
|
||||
b OSClearContext
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// inline duplicates for OSDumpContext to match
|
||||
// maybe need to change inlining compiler flag for better match?
|
||||
inline void i_OSClearContext(OSContext* context) {
|
||||
context->mode = 0;
|
||||
context->state = 0;
|
||||
|
||||
if (context == OS_CURRENT_FPU_CONTEXT) {
|
||||
OS_CURRENT_FPU_CONTEXT = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline OSContext* i_OSGetCurrentContext(void) {
|
||||
return OS_CURRENT_CONTEXT;
|
||||
}
|
||||
|
||||
void OSDumpContext(OSContext* context) {
|
||||
u32 i;
|
||||
u32* p;
|
||||
|
||||
OSReport("------------------------- Context 0x%08x -------------------------\n", context);
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
OSReport("r%-2d = 0x%08x (%14d) r%-2d = 0x%08x (%14d)\n", i, context->gpr[i],
|
||||
context->gpr[i], i + 16, context->gpr[i + 16], context->gpr[i + 16]);
|
||||
}
|
||||
|
||||
OSReport("LR = 0x%08x CR = 0x%08x\n", context->lr, context->cr);
|
||||
OSReport("SRR0 = 0x%08x SRR1 = 0x%08x\n", context->srr0, context->srr1);
|
||||
|
||||
OSReport("\nGQRs----------\n");
|
||||
for (i = 0; i < 4; ++i) {
|
||||
OSReport("gqr%d = 0x%08x \t gqr%d = 0x%08x\n", i, context->gqr[i], i + 4,
|
||||
context->gqr[i + 4]);
|
||||
}
|
||||
|
||||
if (context->state & OS_CONTEXT_STATE_FPSAVED) {
|
||||
OSContext* currentContext;
|
||||
OSContext fpuContext;
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
currentContext = i_OSGetCurrentContext();
|
||||
i_OSClearContext(&fpuContext);
|
||||
OSSetCurrentContext(&fpuContext);
|
||||
|
||||
OSReport("\n\nFPRs----------\n");
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
OSReport("fr%d \t= %d \t fr%d \t= %d\n", i, (u32)context->fpr[i], i + 1,
|
||||
(u32)context->fpr[i + 1]);
|
||||
}
|
||||
OSReport("\n\nPSFs----------\n");
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
OSReport("ps%d \t= 0x%x \t ps%d \t= 0x%x\n", i, (u32)context->ps[i], i + 1,
|
||||
(u32)context->ps[i + 1]);
|
||||
}
|
||||
|
||||
i_OSClearContext(&fpuContext);
|
||||
OSSetCurrentContext(currentContext);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
OSReport("\nAddress: Back Chain LR Save\n");
|
||||
for (i = 0, p = (u32*)context->gpr[1]; p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) {
|
||||
OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static asm void OSSwitchFPUContext(register u8 err, register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mfmsr r5
|
||||
ori r5, r5, 0x2000
|
||||
mtmsr r5
|
||||
isync
|
||||
lwz r5, 0x19c(context)
|
||||
ori r5, r5, 0x2000
|
||||
mtspr 0x1b, r5
|
||||
lis r3, OS_CURRENT_FPU_CONTEXT@ha
|
||||
lwz r5, OS_CURRENT_FPU_CONTEXT@l(r3)
|
||||
stw context, 0xd8(r3)
|
||||
cmpw r5, context
|
||||
beq context_is_curr_fpu_context
|
||||
cmpwi r5, 0
|
||||
beq context_is_null
|
||||
bl __OSSaveFPUContext
|
||||
|
||||
context_is_null:
|
||||
bl __OSLoadFPUContext
|
||||
|
||||
context_is_curr_fpu_context:
|
||||
lwz r3, 0x80(context)
|
||||
mtcrf 0xff, r3
|
||||
lwz r3, 0x84(context)
|
||||
mtlr r3
|
||||
lwz r3, 0x198(context)
|
||||
mtspr 0x1a, r3
|
||||
lwz r3, 0x88(context)
|
||||
mtctr r3
|
||||
lwz r3, 0x8c(context)
|
||||
mtxer r3
|
||||
lhz r3, 0x1a2(context)
|
||||
rlwinm r3, r3, 0, 0x1f, 0x1d
|
||||
sth r3, 0x1a2(context)
|
||||
lwz r5, 0x14(context)
|
||||
lwz r3, 0xc(context)
|
||||
lwz context, 0x10(context)
|
||||
rfi
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void __OSContextInit(void) {
|
||||
__OSSetExceptionHandler(EXCEPTION_FLOATING_POINT, OSSwitchFPUContext);
|
||||
__OSFPUContext = NULL;
|
||||
DBPrintf("FPU-unavailable handler installed\n");
|
||||
}
|
||||
|
||||
asm void OSFillFPUContext(register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mfmsr r5
|
||||
ori r5, r5, 0x2000
|
||||
mtmsr r5
|
||||
isync
|
||||
|
||||
stfd f0, 0x90(context)
|
||||
stfd f1, 0x98(context)
|
||||
stfd f2, 0xa0(context)
|
||||
stfd f3, 0xa8(context)
|
||||
stfd f4, 0xb0(context)
|
||||
stfd f5, 0xb8(context)
|
||||
stfd f6, 0xc0(context)
|
||||
stfd f7, 0xc8(context)
|
||||
stfd f8, 0xd0(context)
|
||||
stfd f9, 0xd8(context)
|
||||
stfd f10, 0xe0(context)
|
||||
stfd f11, 0xe8(context)
|
||||
stfd f12, 0xf0(context)
|
||||
stfd f13, 0xf8(context)
|
||||
stfd f14, 0x100(context)
|
||||
stfd f15, 0x108(context)
|
||||
stfd f16, 0x110(context)
|
||||
stfd f17, 0x118(context)
|
||||
stfd f18, 0x120(context)
|
||||
stfd f19, 0x128(context)
|
||||
stfd f20, 0x130(context)
|
||||
stfd f21, 0x138(context)
|
||||
stfd f22, 0x140(context)
|
||||
stfd f23, 0x148(context)
|
||||
stfd f24, 0x150(context)
|
||||
stfd f25, 0x158(context)
|
||||
stfd f26, 0x160(context)
|
||||
stfd f27, 0x168(context)
|
||||
stfd f28, 0x170(context)
|
||||
stfd f29, 0x178(context)
|
||||
stfd f30, 0x180(context)
|
||||
stfd f31, 0x188(context)
|
||||
|
||||
mffs f0
|
||||
stfd f0, 0x190(context)
|
||||
lfd f0, 0x90(context)
|
||||
mfspr r5, 0x398
|
||||
rlwinm. r5, r5, 3, 0x1f, 0x1f
|
||||
beq exit
|
||||
|
||||
psq_st f0, 456(context), 0, 0
|
||||
psq_st f1, 464(context), 0, 0
|
||||
psq_st f2, 472(context), 0, 0
|
||||
psq_st f3, 480(context), 0, 0
|
||||
psq_st f4, 488(context), 0, 0
|
||||
psq_st f5, 496(context), 0, 0
|
||||
psq_st f6, 504(context), 0, 0
|
||||
psq_st f7, 512(context), 0, 0
|
||||
psq_st f8, 520(context), 0, 0
|
||||
psq_st f9, 528(context), 0, 0
|
||||
psq_st f10, 536(context), 0, 0
|
||||
psq_st f11, 544(context), 0, 0
|
||||
psq_st f12, 552(context), 0, 0
|
||||
psq_st f13, 560(context), 0, 0
|
||||
psq_st f14, 568(context), 0, 0
|
||||
psq_st f15, 576(context), 0, 0
|
||||
psq_st f16, 584(context), 0, 0
|
||||
psq_st f17, 592(context), 0, 0
|
||||
psq_st f18, 600(context), 0, 0
|
||||
psq_st f19, 608(context), 0, 0
|
||||
psq_st f20, 616(context), 0, 0
|
||||
psq_st f21, 624(context), 0, 0
|
||||
psq_st f22, 632(context), 0, 0
|
||||
psq_st f23, 640(context), 0, 0
|
||||
psq_st f24, 648(context), 0, 0
|
||||
psq_st f25, 656(context), 0, 0
|
||||
psq_st f26, 664(context), 0, 0
|
||||
psq_st f27, 672(context), 0, 0
|
||||
psq_st f28, 680(context), 0, 0
|
||||
psq_st f29, 688(context), 0, 0
|
||||
psq_st f30, 696(context), 0, 0
|
||||
psq_st f31, 704(context), 0, 0
|
||||
|
||||
exit:
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
227
src/dolphin/os/OSError.c
Normal file
227
src/dolphin/os/OSError.c
Normal file
@ -0,0 +1,227 @@
|
||||
#include "dolphin/os/OSError.h"
|
||||
#include "dolphin/base/PPCArch.h"
|
||||
#include "dolphin/dsp.h"
|
||||
#include "dolphin/dvd/dvdlow.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
OSThread* __OSCurrentThread : (OS_BASE_CACHED | 0x00E4);
|
||||
OSThreadQueue __OSActiveThreadQueue : (OS_BASE_CACHED | 0x00DC);
|
||||
volatile OSContext* __OSFPUContext : (OS_BASE_CACHED | 0x00D8);
|
||||
|
||||
extern volatile u32 __OSLastInterruptSrr0;
|
||||
extern volatile s16 __OSLastInterrupt;
|
||||
extern volatile OSTime __OSLastInterruptTime;
|
||||
|
||||
extern OSErrorHandlerEx __OSErrorTable[16];
|
||||
OSErrorHandlerEx __OSErrorTable[16];
|
||||
|
||||
#define FPSCR_ENABLE (FPSCR_VE | FPSCR_OE | FPSCR_UE | FPSCR_ZE | FPSCR_XE)
|
||||
extern u32 __OSFpscrEnableBits = FPSCR_ENABLE;
|
||||
|
||||
__declspec(weak) void OSReport(const char* msg, ...) {
|
||||
va_list marker;
|
||||
|
||||
va_start(marker, msg);
|
||||
vprintf(msg, marker);
|
||||
va_end(marker);
|
||||
}
|
||||
|
||||
__declspec(weak) void OSVReport(const char* msg, va_list list) {
|
||||
vprintf(msg, list);
|
||||
}
|
||||
|
||||
__declspec(weak) void OSPanic(const char* file, s32 line, const char* msg, ...) {
|
||||
va_list marker;
|
||||
u32 i;
|
||||
u32* p;
|
||||
|
||||
OSDisableInterrupts();
|
||||
va_start(marker, msg);
|
||||
vprintf(msg, marker);
|
||||
va_end(marker);
|
||||
OSReport(" in \"%s\" on line %d.\n", file, line);
|
||||
|
||||
// actually useful for debugging- stack crawl
|
||||
OSReport("\nAddress: Back Chain LR Save\n");
|
||||
for (i = 0, p = (u32*)OSGetStackPointer(); // get current stack pointer
|
||||
p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) // get caller stack pointer
|
||||
{
|
||||
OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]);
|
||||
}
|
||||
|
||||
PPCHalt();
|
||||
}
|
||||
|
||||
OSErrorHandler OSSetErrorHandler(OSError error, OSErrorHandler handler) {
|
||||
OSErrorHandlerEx oldHandler;
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
oldHandler = __OSErrorTable[error];
|
||||
__OSErrorTable[error] = (OSErrorHandlerEx)handler;
|
||||
|
||||
if (error == EXCEPTION_FLOATING_POINT_EXCEPTION) {
|
||||
u32 msr;
|
||||
u32 fpscr;
|
||||
OSThread* thread;
|
||||
|
||||
msr = PPCMfmsr();
|
||||
PPCMtmsr(msr | MSR_FP);
|
||||
fpscr = PPCMffpscr();
|
||||
if (handler) {
|
||||
for (thread = __OSActiveThreadQueue.head; thread;
|
||||
thread = thread->active_threads_link.next)
|
||||
{
|
||||
thread->context.srr1 |= MSR_FE0 | MSR_FE1;
|
||||
if ((thread->context.state & OS_CONTEXT_STATE_FPSAVED) == 0) {
|
||||
int i;
|
||||
thread->context.state |= OS_CONTEXT_STATE_FPSAVED;
|
||||
for (i = 0; i < 32; ++i) {
|
||||
*(u64*)&thread->context.fpr[i] = (u64)0xffffffffffffffffLL;
|
||||
*(u64*)&thread->context.ps[i] = (u64)0xffffffffffffffffLL;
|
||||
}
|
||||
thread->context.fpscr = FPSCR_NI;
|
||||
}
|
||||
thread->context.fpscr |= __OSFpscrEnableBits & FPSCR_ENABLE;
|
||||
thread->context.fpscr &=
|
||||
~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI |
|
||||
FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX |
|
||||
FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI);
|
||||
}
|
||||
fpscr |= __OSFpscrEnableBits & FPSCR_ENABLE;
|
||||
msr |= MSR_FE0 | MSR_FE1;
|
||||
} else {
|
||||
for (thread = __OSActiveThreadQueue.head; thread;
|
||||
thread = thread->active_threads_link.next)
|
||||
{
|
||||
thread->context.srr1 &= ~(MSR_FE0 | MSR_FE1);
|
||||
thread->context.fpscr &= ~FPSCR_ENABLE;
|
||||
thread->context.fpscr &=
|
||||
~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI |
|
||||
FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX |
|
||||
FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI);
|
||||
}
|
||||
fpscr &= ~FPSCR_ENABLE;
|
||||
msr &= ~(MSR_FE0 | MSR_FE1);
|
||||
}
|
||||
|
||||
fpscr &= ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI |
|
||||
FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | FPSCR_ZX |
|
||||
FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI);
|
||||
|
||||
PPCMtfpscr(fpscr);
|
||||
PPCMtmsr(msr);
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar) {
|
||||
OSTime now;
|
||||
|
||||
now = OSGetTime();
|
||||
|
||||
if (!(context->srr1 & 2)) {
|
||||
OSReport("Non-recoverable Exception %d", exception);
|
||||
|
||||
} else {
|
||||
if (exception == EXCEPTION_PROGRAM && (context->srr1 & (0x80000000 >> 11)) &&
|
||||
__OSErrorTable[EXCEPTION_FLOATING_POINT_EXCEPTION] != 0)
|
||||
{
|
||||
u32 fpscr;
|
||||
u32 msr;
|
||||
|
||||
exception = EXCEPTION_FLOATING_POINT_EXCEPTION;
|
||||
|
||||
msr = PPCMfmsr();
|
||||
PPCMtmsr(msr | 0x2000);
|
||||
|
||||
if (__OSFPUContext) {
|
||||
OSSaveFPUContext((OSContext*)__OSFPUContext);
|
||||
}
|
||||
|
||||
fpscr = PPCMffpscr();
|
||||
fpscr &= ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI |
|
||||
FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX |
|
||||
FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI);
|
||||
PPCMtfpscr(fpscr);
|
||||
|
||||
PPCMtmsr(msr);
|
||||
|
||||
if (__OSFPUContext == context) {
|
||||
OSDisableScheduler();
|
||||
__OSErrorTable[exception](exception, context, dsisr, dar);
|
||||
context->srr1 &= ~0x2000;
|
||||
__OSFPUContext = NULL;
|
||||
|
||||
context->fpscr &=
|
||||
~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI |
|
||||
FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX |
|
||||
FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI);
|
||||
OSEnableScheduler();
|
||||
__OSReschedule();
|
||||
} else {
|
||||
context->srr1 &= ~0x2000;
|
||||
__OSFPUContext = NULL;
|
||||
}
|
||||
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
if (__OSErrorTable[exception]) {
|
||||
OSDisableScheduler();
|
||||
__OSErrorTable[exception](exception, context, dsisr, dar);
|
||||
OSEnableScheduler();
|
||||
__OSReschedule();
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
if (exception == OS_ERROR_DECREMENTER) {
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
OSReport("Unhandled Exception %d", exception);
|
||||
}
|
||||
|
||||
OSReport("\n");
|
||||
OSDumpContext(context);
|
||||
OSReport("\nDSISR = 0x%08x DAR = 0x%08x\n", dsisr, dar);
|
||||
OSReport("TB = 0x%016llx\n", now);
|
||||
|
||||
switch (exception) {
|
||||
case EXCEPTION_DSI:
|
||||
OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access "
|
||||
"invalid address 0x%x (read from DAR)\n",
|
||||
context->srr0, dar);
|
||||
break;
|
||||
case EXCEPTION_ISI:
|
||||
OSReport("\nAttempted to fetch instruction from invalid address 0x%x "
|
||||
"(read from SRR0)\n",
|
||||
context->srr0);
|
||||
break;
|
||||
case EXCEPTION_ALIGNMENT:
|
||||
OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access "
|
||||
"unaligned address 0x%x (read from DAR)\n",
|
||||
context->srr0, dar);
|
||||
break;
|
||||
case EXCEPTION_PROGRAM:
|
||||
OSReport("\nProgram exception : Possible illegal instruction/operation "
|
||||
"at or around 0x%x (read from SRR0)\n",
|
||||
context->srr0, dar);
|
||||
break;
|
||||
case EXCEPTION_MEMORY_PROTECTION:
|
||||
OSReport("\n");
|
||||
OSReport("AI DMA Address = 0x%04x%04x\n", __DSPRegs[DSP_DMA_START_HI],
|
||||
__DSPRegs[DSP_DMA_START_LO]);
|
||||
OSReport("ARAM DMA Address = 0x%04x%04x\n", __DSPRegs[DSP_ARAM_DMA_MM_HI],
|
||||
__DSPRegs[DSP_ARAM_DMA_MM_LO]);
|
||||
OSReport("DI DMA Address = 0x%08x\n", __DIRegs[5]);
|
||||
break;
|
||||
}
|
||||
|
||||
OSReport("\nLast interrupt (%d): SRR0 = 0x%08x TB = 0x%016llx\n", __OSLastInterrupt,
|
||||
__OSLastInterruptSrr0, __OSLastInterruptTime);
|
||||
|
||||
PPCHalt();
|
||||
}
|
299
src/dolphin/os/OSExec.c
Normal file
299
src/dolphin/os/OSExec.c
Normal file
@ -0,0 +1,299 @@
|
||||
//
|
||||
// Generated By: dol2asm
|
||||
// Translation Unit: OSExec
|
||||
//
|
||||
|
||||
#include "dolphin/os/OSExec.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
#include "dolphin/ai.h"
|
||||
#include "dol2asm.h"
|
||||
#include "string.h"
|
||||
#include "printf.h"
|
||||
|
||||
#pragma push
|
||||
#pragma optimization_level 0
|
||||
#pragma optimizewithasm off
|
||||
static asm s32 PackArgs(void* param_0, u32 param_1, void* param_2) {
|
||||
nofralloc
|
||||
#include "asm/dolphin/os/OSExec/PackArgs.s"
|
||||
}
|
||||
#pragma pop
|
||||
|
||||
static asm void Run(int param_0) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mflr r0
|
||||
stw r0, 4(r1)
|
||||
stwu r1, -0x18(r1)
|
||||
stw r31, 0x14(r1)
|
||||
mr r31, r3
|
||||
bl ICFlashInvalidate
|
||||
sync
|
||||
isync
|
||||
mtlr r31
|
||||
blr
|
||||
|
||||
lwz r0, 0x1c(r1)
|
||||
lwz r31, 0x14(r1)
|
||||
addi r1, r1, 0x18
|
||||
mtlr r0
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static void ReadDisc(void* param_0, s32 param_1, s32 param_2) {
|
||||
DVDCommandBlock cmd;
|
||||
DVDReadAbsAsyncPrio(&cmd, param_0, param_1, param_2, NULL, 0);
|
||||
while (DVDGetCommandBlockStatus(&cmd)) {
|
||||
if (!DVDCheckDisk()) {
|
||||
__OSDoHotReset(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL Prepared;
|
||||
|
||||
static void Callback(void) {
|
||||
Prepared = TRUE;
|
||||
}
|
||||
|
||||
OSExecParams* osExecParams : 0x800030f0;
|
||||
|
||||
void __OSGetExecParams(OSExecParams* param_0) {
|
||||
if (OSPhysicalToCached(0) <= osExecParams) {
|
||||
memcpy(param_0, osExecParams, sizeof(OSExecParams));
|
||||
} else {
|
||||
param_0->valid = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static __OSSetExecParams(const OSExecParams* src, OSExecParams* dst) {
|
||||
memcpy(dst, src, sizeof(OSExecParams));
|
||||
osExecParams = dst;
|
||||
}
|
||||
|
||||
static s32 apploaderPosition;
|
||||
|
||||
s32 appLoaderOffset : 0x800030f4;
|
||||
|
||||
static int GetApploaderPosition(void) {
|
||||
u8 padding[8];
|
||||
|
||||
if (apploaderPosition != 0) {
|
||||
return apploaderPosition;
|
||||
}
|
||||
|
||||
if (appLoaderOffset) {
|
||||
void* buffer = OSAllocFromArenaLo(0x40, 0x20);
|
||||
ReadDisc(buffer, 0x40, appLoaderOffset);
|
||||
apploaderPosition = appLoaderOffset + ((s32*)buffer)[0xe];
|
||||
} else {
|
||||
apploaderPosition = 0x2440;
|
||||
}
|
||||
return apploaderPosition;
|
||||
}
|
||||
|
||||
SECTION_DATA static char lit_115[] = "2004/02/01";
|
||||
|
||||
// GetApploaderPosition inline issue + end of function
|
||||
#ifdef NONMATCHING
|
||||
|
||||
typedef int (*AppLoaderInnerCallback)(void*, s32*, s32*);
|
||||
typedef void (*LogCallback)(void*);
|
||||
typedef void (*AppLoaderCallback)(LogCallback*, AppLoaderInnerCallback*, int (**callback)(void));
|
||||
|
||||
typedef struct {
|
||||
char version[10];
|
||||
s16 field_0xa;
|
||||
s32 field_0xc;
|
||||
AppLoaderCallback field_0x10;
|
||||
s32 field_0x14;
|
||||
s32 field_0x18;
|
||||
s32 field_0x1c;
|
||||
} AppLoaderStruct;
|
||||
|
||||
static AppLoaderStruct* LoadApploader() {
|
||||
AppLoaderStruct* iVar1;
|
||||
s32 pos;
|
||||
s32 nextPos;
|
||||
|
||||
iVar1 = (AppLoaderStruct*)OSAllocFromArenaLo(sizeof(AppLoaderStruct), sizeof(AppLoaderStruct));
|
||||
pos = GetApploaderPosition();
|
||||
ReadDisc(iVar1, sizeof(AppLoaderStruct), pos);
|
||||
nextPos = GetApploaderPosition();
|
||||
ReadDisc((void*)0x81200000, iVar1->field_0x14 + 0x1fU & 0xffffffe0, nextPos + 0x20);
|
||||
ICInvalidateRange((void*)0x81200000, iVar1->field_0x14 + 0x1fU & 0xffffffe0);
|
||||
return iVar1;
|
||||
}
|
||||
|
||||
static BOOL IsNewApploader(const char* version) {
|
||||
BOOL rv;
|
||||
if (strncmp(version, "2004/02/01", 10) > 0) {
|
||||
rv = TRUE;
|
||||
} else {
|
||||
rv = FALSE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int LoadDol(OSExecParams* def, AppLoaderCallback cb) {
|
||||
LogCallback local_c;
|
||||
AppLoaderInnerCallback innercb;
|
||||
int (*local_14)(void);
|
||||
OSExecParams* execParams;
|
||||
void* local_18;
|
||||
s32 local_1c;
|
||||
s32 local_20;
|
||||
cb(&local_c, &innercb, &local_14);
|
||||
execParams = OSAllocFromArenaLo(sizeof(OSExecParams), 1);
|
||||
__OSSetExecParams(def, execParams);
|
||||
local_c(OSReport);
|
||||
OSSetArenaLo(execParams);
|
||||
while (innercb(&local_18, &local_1c, &local_20)) {
|
||||
ReadDisc(local_18, local_1c, local_20);
|
||||
}
|
||||
return (*local_14)();
|
||||
}
|
||||
|
||||
static void StartDol(OSExecParams* execParams, int param_1) {
|
||||
OSExecParams* uVar1 = (OSExecParams*)OSAllocFromArenaLo(sizeof(OSExecParams), 1);
|
||||
__OSSetExecParams(execParams, uVar1);
|
||||
__PIRegs[9] = 7;
|
||||
OSDisableInterrupts();
|
||||
Run(param_1);
|
||||
}
|
||||
|
||||
u8 DAT_800030e2 : 0x800030E2;
|
||||
|
||||
void __OSBootDolSimple(u32 param_0, u32 param_1, void* param_2, void* param_3, s32 param_4, u32 param_5, void* param_6) {
|
||||
OSExecParams* puVar1;
|
||||
AppLoaderStruct* iVar3;
|
||||
DVDDiskID* id;
|
||||
int uVar2;
|
||||
s32 iVar4;
|
||||
s32 is_streaming;
|
||||
DVDCommandBlock cmd;
|
||||
|
||||
OSDisableInterrupts();
|
||||
puVar1 = (OSExecParams*)OSAllocFromArenaLo(sizeof(OSExecParams), 1);
|
||||
puVar1->valid = 1;
|
||||
puVar1->restartCode = param_1;
|
||||
puVar1->regionStart = param_2;
|
||||
puVar1->regionEnd = param_3;
|
||||
puVar1->argsUseDefault = param_4;
|
||||
if (param_4 == 0) {
|
||||
puVar1->argsAddr = OSAllocFromArenaLo(0x2000, 1);
|
||||
PackArgs(puVar1->argsAddr, param_5, param_6);
|
||||
}
|
||||
DVDInit();
|
||||
DVDSetAutoInvalidation(TRUE);
|
||||
DVDResume();
|
||||
Prepared = FALSE;
|
||||
__DVDPrepareResetAsync((DVDCBCallback)Callback);
|
||||
__OSMaskInterrupts(0xffffffe0);
|
||||
__OSUnmaskInterrupts(0x400);
|
||||
OSEnableInterrupts();
|
||||
while (Prepared != TRUE) {
|
||||
if (!DVDCheckDisk()) {
|
||||
__OSDoHotReset(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!__OSIsGcam) {
|
||||
id = DVDGetCurrentDiskID();
|
||||
if (id->is_streaming) {
|
||||
is_streaming = TRUE;
|
||||
} else {
|
||||
is_streaming = FALSE;
|
||||
}
|
||||
if (is_streaming) {
|
||||
AISetStreamVolLeft(0);
|
||||
AISetStreamVolRight(0);
|
||||
DVDCancelStreamAsync(&cmd, NULL);
|
||||
while (DVDGetCommandBlockStatus(&cmd)) {
|
||||
if (!DVDCheckDisk()) {
|
||||
__OSDoHotReset(0);
|
||||
}
|
||||
}
|
||||
AISetStreamPlayState(0);
|
||||
}
|
||||
}
|
||||
|
||||
iVar3 = LoadApploader();
|
||||
if (IsNewApploader(iVar3->version)) {
|
||||
if (param_0 == -1) {
|
||||
param_0 = GetApploaderPosition();
|
||||
param_0 += iVar3->field_0x14;
|
||||
param_0 += 0x20;
|
||||
}
|
||||
puVar1->bootDol = param_0;
|
||||
uVar2 = LoadDol(puVar1, iVar3->field_0x10);
|
||||
StartDol(puVar1, uVar2);
|
||||
} else {
|
||||
BOOT_REGION_START = (u32)param_2;
|
||||
BOOT_REGION_END = (u32)param_3;
|
||||
DAT_800030e2 = 1;
|
||||
// GetApploaderPosition is inlined for some reason
|
||||
iVar4 = GetApploaderPosition() + iVar3->field_0x14;
|
||||
ReadDisc((void*)0x81300000, iVar3->field_0x18 + 0x1fU & 0xffffffe0,
|
||||
iVar4 + 0x20);
|
||||
ICInvalidateRange((void*)0x81300000, iVar3->field_0x18 + 0x1fU & 0xffffffe0);
|
||||
OSDisableInterrupts();
|
||||
ICFlashInvalidate();
|
||||
Run(0x81300000);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#pragma push
|
||||
#pragma optimization_level 0
|
||||
#pragma optimizewithasm off
|
||||
asm void __OSBootDolSimple(u32 param_0, u32 param_1, void* param_2, void* param_3, s32 param_4, u32 param_5, void* param_6) {
|
||||
nofralloc
|
||||
#include "asm/dolphin/os/OSExec/__OSBootDolSimple.s"
|
||||
}
|
||||
#pragma pop
|
||||
#endif
|
||||
|
||||
SECTION_SDATA static char lit_213[] = "%d";
|
||||
|
||||
#ifdef NONMATCHING
|
||||
void __OSBootDol(s32 param_0, u32 param_1, char** param_2) {
|
||||
char acStack_28[20];
|
||||
void* local_2c;
|
||||
void* local_30;
|
||||
s32 iVar3;
|
||||
char** ppcVar1;
|
||||
char** ppcVar2;
|
||||
char** ppcVarDst;
|
||||
char** ppcVarSrc;
|
||||
int iVar2;
|
||||
OSGetSaveRegion(&local_2c, &local_30);
|
||||
sprintf(acStack_28, "%d", param_0);
|
||||
iVar3 = 0;
|
||||
if (param_2 != NULL) {
|
||||
ppcVar2 = param_2;
|
||||
while (*ppcVar2 != NULL) {
|
||||
ppcVar2++;
|
||||
iVar3++;
|
||||
}
|
||||
}
|
||||
ppcVar1 = (char**)OSAllocFromArenaLo((iVar3 + 2) * 4, 1);
|
||||
*ppcVar1 = acStack_28;
|
||||
ppcVarSrc = param_2;
|
||||
ppcVarDst = ppcVar1 + 1;
|
||||
for (iVar2 = 1; iVar2 < iVar3 + 1; iVar2++) {
|
||||
*ppcVarDst++ = *ppcVarSrc++;
|
||||
}
|
||||
__OSBootDolSimple(0xffffffff, param_1, local_2c, local_30, 0, iVar3 + 1, ppcVar1);
|
||||
}
|
||||
#else
|
||||
#pragma push
|
||||
#pragma optimization_level 0
|
||||
#pragma optimizewithasm off
|
||||
asm void __OSBootDol(s32 param_0, u32 param_1, char** param_2) {
|
||||
nofralloc
|
||||
#include "asm/dolphin/os/OSExec/__OSBootDol.s"
|
||||
}
|
||||
#pragma pop
|
||||
#endif
|
303
src/dolphin/os/OSFont.c
Normal file
303
src/dolphin/os/OSFont.c
Normal file
@ -0,0 +1,303 @@
|
||||
#include "dolphin/os/OSFont.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
#include "dolphin/vi/vi.h"
|
||||
|
||||
static u16 HankakuToCode[192] = {
|
||||
0x020C, 0x020D, 0x020E, 0x020F, 0x0210, 0x0211, 0x0212, 0x0213,
|
||||
0x0214, 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021A, 0x021B,
|
||||
0x021C, 0x021D, 0x021E, 0x021F, 0x0220, 0x0221, 0x0222, 0x0223,
|
||||
0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022A, 0x022B,
|
||||
0x022C, 0x022D, 0x022E, 0x022F, 0x0230, 0x0231, 0x0232, 0x0233,
|
||||
0x0234, 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023A, 0x023B,
|
||||
0x023C, 0x023D, 0x023E, 0x023F, 0x0240, 0x0241, 0x0242, 0x0243,
|
||||
0x0244, 0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024A, 0x024B,
|
||||
0x024C, 0x024D, 0x024E, 0x024F, 0x0250, 0x0251, 0x0252, 0x0253,
|
||||
0x0254, 0x0255, 0x0256, 0x0257, 0x0258, 0x0259, 0x025A, 0x025B,
|
||||
0x025C, 0x025D, 0x025E, 0x025F, 0x0260, 0x0261, 0x0262, 0x0263,
|
||||
0x0264, 0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026A, 0x020C,
|
||||
0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C,
|
||||
0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C,
|
||||
0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C,
|
||||
0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C,
|
||||
0x020C, 0x026B, 0x026C, 0x026D, 0x026E, 0x026F, 0x0270, 0x0271,
|
||||
0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278, 0x0279,
|
||||
0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F, 0x0280, 0x0281,
|
||||
0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289,
|
||||
0x028A, 0x028B, 0x028C, 0x028D, 0x028E, 0x028F, 0x0290, 0x0291,
|
||||
0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, 0x0298, 0x0299,
|
||||
0x029A, 0x029B, 0x029C, 0x029D, 0x029E, 0x029F, 0x02A0, 0x02A1,
|
||||
0x02A2, 0x02A3, 0x02A4, 0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9,
|
||||
};
|
||||
|
||||
static u16 Zenkaku2Code[1221] = {
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
|
||||
0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
|
||||
0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
|
||||
0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
|
||||
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||
0x0068, 0x0069, 0x006A, 0x006B, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x006C,
|
||||
0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0074,
|
||||
0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080, 0x0081,
|
||||
0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x008A,
|
||||
0x008B, 0x008C, 0x008D, 0x008E, 0x008F, 0x0090, 0x0091, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0092, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x009D, 0x009E, 0x009F, 0x00A0,
|
||||
0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8,
|
||||
0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0,
|
||||
0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x00B7, 0x00B8, 0x00B9, 0x00BA,
|
||||
0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2,
|
||||
0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA,
|
||||
0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6,
|
||||
0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE,
|
||||
0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6,
|
||||
0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE,
|
||||
0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6,
|
||||
0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE,
|
||||
0x00FF, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
|
||||
0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E,
|
||||
0x010F, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
|
||||
0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E,
|
||||
0x011F, 0x0120, 0x0121, 0x0122, 0x0123, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0124, 0x0125, 0x0126, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B,
|
||||
0x012C, 0x012D, 0x012E, 0x012F, 0x0130, 0x0131, 0x0132, 0x0133,
|
||||
0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B,
|
||||
0x013C, 0x013D, 0x013E, 0x013F, 0x0140, 0x0141, 0x0142, 0x0143,
|
||||
0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x014A, 0x014B,
|
||||
0x014C, 0x014D, 0x014E, 0x014F, 0x0150, 0x0151, 0x0152, 0x0153,
|
||||
0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B,
|
||||
0x015C, 0x015D, 0x015E, 0x015F, 0x0160, 0x0161, 0x0162, 0x0163,
|
||||
0x0164, 0x0165, 0x0166, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B,
|
||||
0x016C, 0x016D, 0x016E, 0x016F, 0x0170, 0x0171, 0x0172, 0x0173,
|
||||
0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017A, 0x017B,
|
||||
0x017C, 0x017D, 0x017E, 0x017F, 0x0180, 0x0181, 0x0182, 0x0183,
|
||||
0x0184, 0x0185, 0x0186, 0x0187, 0x0188, 0x0189, 0x018A, 0x018B,
|
||||
0x018C, 0x018D, 0x018E, 0x018F, 0x0190, 0x0191, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0193,
|
||||
0x0194, 0x0195, 0x0196, 0x0197, 0x0198, 0x0199, 0x019A, 0x019B,
|
||||
0x019C, 0x019D, 0x019E, 0x019F, 0x01A0, 0x01A1, 0x01A2, 0x01A3,
|
||||
0x01A4, 0x01A5, 0x01A6, 0x01A7, 0x01A8, 0x01A9, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x01AA, 0x01AB, 0x01AC, 0x01AD,
|
||||
0x01AE, 0x01AF, 0x01B0, 0x01B1, 0x01B2, 0x01B3, 0x01B4, 0x01B5,
|
||||
0x01B6, 0x01B7, 0x01B8, 0x01B9, 0x01BA, 0x01BB, 0x01BC, 0x01BD,
|
||||
0x01BE, 0x01BF, 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C5,
|
||||
0x01C6, 0x01C7, 0x01C8, 0x01C9, 0x01CA, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x01CB, 0x01CC, 0x01CD, 0x01CE,
|
||||
0x01CF, 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6,
|
||||
0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE,
|
||||
0x01DF, 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E4, 0x01E5, 0x01E6,
|
||||
0x01E7, 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x01EC, 0x01ED, 0x01EE, 0x01EF, 0x01F0, 0x01F1,
|
||||
0x01F2, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9,
|
||||
0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF, 0x0200, 0x0201,
|
||||
0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209,
|
||||
0x020A, 0x020B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x020C,
|
||||
0x020D, 0x020E, 0x020F, 0x0210, 0x0211, 0x0212, 0x0213, 0x0214,
|
||||
0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021A, 0x021B, 0x021C,
|
||||
0x021D, 0x021E, 0x021F, 0x0220, 0x0221, 0x0222, 0x0223, 0x0224,
|
||||
0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022A, 0x022B, 0x022C,
|
||||
0x022D, 0x022E, 0x022F, 0x0230, 0x0231, 0x0232, 0x0233, 0x0234,
|
||||
0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023A, 0x023B, 0x023C,
|
||||
0x023D, 0x023E, 0x023F, 0x0240, 0x0241, 0x0242, 0x0243, 0x0244,
|
||||
0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024A, 0x024B, 0x024C,
|
||||
0x024D, 0x024E, 0x024F, 0x0250, 0x0251, 0x0252, 0x0253, 0x0254,
|
||||
0x0255, 0x0256, 0x0257, 0x0258, 0x0259, 0x025A, 0x025B, 0x025C,
|
||||
0x025D, 0x025E, 0x025F, 0x0260, 0x0261, 0x0262, 0x0263, 0x0264,
|
||||
0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026A, 0x026B, 0x026C,
|
||||
0x026D, 0x026E, 0x026F, 0x0270, 0x0271, 0x0272, 0x0273, 0x0274,
|
||||
0x0275, 0x0276, 0x0277, 0x0278, 0x0279, 0x027A, 0x027B, 0x027C,
|
||||
0x027D, 0x027E, 0x027F, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284,
|
||||
0x0285, 0x0286, 0x0287, 0x0288, 0x0289, 0x028A, 0x028B, 0x028C,
|
||||
0x028D, 0x028E, 0x028F, 0x0290, 0x0291, 0x0292, 0x0293, 0x0294,
|
||||
0x0295, 0x0296, 0x0297, 0x0298, 0x0299, 0x029A, 0x029B, 0x029C,
|
||||
0x029D, 0x029E, 0x029F, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x02A4,
|
||||
0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x02AC,
|
||||
0x02AD, 0x02AE, 0x02AF, 0x02B0, 0x02B1, 0x02B2, 0x02B3, 0x02B4,
|
||||
0x02B5, 0x02B6, 0x02B7, 0x02B8, 0x02B9, 0x02BA, 0x02BB, 0x02BC,
|
||||
0x02BD, 0x02BE, 0x02BF, 0x02C0, 0x02C1, 0x02C2, 0x02C3, 0x02C4,
|
||||
0x02C5, 0x02C6, 0x02C7, 0x02C8, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x02C9, 0x02CA, 0x02CB, 0x02CC, 0x02CD, 0x02CE, 0x02CF, 0x02D0,
|
||||
0x02D1, 0x02D2, 0x02D3, 0x02D4, 0x02D5, 0x02D6, 0x02D7, 0x02D8,
|
||||
0x02D9, 0x02DA, 0x02DB, 0x02DC, 0x02DD, 0x02DE, 0x02DF, 0x02E0,
|
||||
0x02E1, 0x02E2, 0x02E3, 0x02E4, 0x02E5, 0x02E6, 0x0000, 0x02E7,
|
||||
0x02E8, 0x02E9, 0x02EA, 0x02EB, 0x02EC, 0x02ED, 0x02EE, 0x02EF,
|
||||
0x02F0, 0x02F1, 0x02F2, 0x02F3, 0x02F4, 0x02F5, 0x02F6, 0x02F7,
|
||||
0x02F8, 0x02F9, 0x02FA, 0x02FB, 0x02FC, 0x02FD, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x02FE, 0x02FF,
|
||||
0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
|
||||
0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
|
||||
0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
|
||||
0x0318, 0x0319, 0x031A, 0x031B, 0x0000,
|
||||
};
|
||||
|
||||
static BOOL IsSjisLeadByte(u8 ch) {
|
||||
return (0x81 <= ch && ch <= 0x9F) || (0xE0 <= ch && ch <= 0xFC);
|
||||
}
|
||||
|
||||
static BOOL IsSjisTrailByte(u8 ch) {
|
||||
return (0x40 <= ch && ch <= 0xFC) && (ch != 0x7F);
|
||||
}
|
||||
|
||||
static u32 GetFontCode(u16 encode, u16 code) {
|
||||
u32 tmp;
|
||||
s32 trail;
|
||||
|
||||
if (encode == OS_FONT_ENCODE_SJIS) {
|
||||
if (0x20 <= code && code <= 0xDF) {
|
||||
return HankakuToCode[code - 0x20];
|
||||
} else if (0x889E < code && code <= 0x9872) {
|
||||
tmp = ((code >> 8) - 0x88) * 0xBC;
|
||||
trail = code & 0xFF;
|
||||
|
||||
if (!IsSjisTrailByte(trail)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
trail -= 0x40;
|
||||
if (trail >= 0x40) {
|
||||
trail--;
|
||||
}
|
||||
|
||||
return tmp + trail + 0x2BE;
|
||||
} else if (0x8140 <= code && code < 0x879E) {
|
||||
tmp = ((code >> 8) - 0x81) * 0xBC;
|
||||
trail = code & 0xFF;
|
||||
|
||||
if (!IsSjisTrailByte(trail)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
trail -= 0x40;
|
||||
if (trail >= 0x40) {
|
||||
trail--;
|
||||
}
|
||||
|
||||
return Zenkaku2Code[tmp + trail];
|
||||
}
|
||||
} else if (code > 0x20 && code <= 0xFF) {
|
||||
return code - 0x20;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 FontEncode = 0xFFFF;
|
||||
|
||||
static OSFontHeader* FontDataAnsi;
|
||||
|
||||
static OSFontHeader* FontDataSjis;
|
||||
|
||||
static void* ParseString;
|
||||
|
||||
u16 OSGetFontEncode(void) {
|
||||
if (FontEncode != 0xFFFF) {
|
||||
return FontEncode;
|
||||
}
|
||||
|
||||
switch (*(u32*)OSPhysicalToCached(0xCC)) {
|
||||
case VI_NTSC:
|
||||
FontEncode = ((__VIRegs[55] & 2) != 0)
|
||||
? 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;
|
||||
}
|
||||
|
||||
ParseString = ParseStringS;
|
||||
|
||||
return FontEncode;
|
||||
}
|
||||
|
||||
static const u8* ParseStringS(u16 encode, const u8* str, OSFontHeader** fontOut,
|
||||
u32* codeOut) {
|
||||
OSFontHeader* font;
|
||||
u16 code = 0;
|
||||
|
||||
switch (encode) {
|
||||
case OS_FONT_ENCODE_ANSI:
|
||||
font = FontDataAnsi;
|
||||
code = *str;
|
||||
if (code != 0) {
|
||||
str++;
|
||||
}
|
||||
break;
|
||||
case OS_FONT_ENCODE_SJIS:
|
||||
font = FontDataSjis;
|
||||
code = *str;
|
||||
if (code == 0) {
|
||||
break;
|
||||
}
|
||||
str++;
|
||||
|
||||
if (IsSjisLeadByte(code) && IsSjisTrailByte(*str)) {
|
||||
code = (code << 8 | *str++);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*fontOut = font;
|
||||
*codeOut = GetFontCode(encode, code);
|
||||
|
||||
return str;
|
||||
}
|
430
src/dolphin/os/OSInterrupt.c
Normal file
430
src/dolphin/os/OSInterrupt.c
Normal file
@ -0,0 +1,430 @@
|
||||
#include "dolphin/os/OSInterrupt.h"
|
||||
#include "dolphin/dsp.h"
|
||||
#include "dolphin/exi/EXIBios.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
vu32 __PIRegs[12] : 0xCC003000;
|
||||
vu16 __MEMRegs[64] : 0xCC004000;
|
||||
|
||||
asm BOOL OSDisableInterrupts(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
entry __RAS_OSDisableInterrupts_begin
|
||||
|
||||
mfmsr r3
|
||||
// Clear external interrupts bit
|
||||
rlwinm r4, r3, 0, 17, 15
|
||||
mtmsr r4
|
||||
|
||||
entry __RAS_OSDisableInterrupts_end
|
||||
|
||||
// Return old interrupt status
|
||||
rlwinm r3, r3, 17, 31, 31
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm BOOL OSEnableInterrupts(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mfmsr r3
|
||||
// Set external interrupts bit
|
||||
ori r4, r3, (1 << 15)
|
||||
mtmsr r4
|
||||
|
||||
// Return old interrupt status
|
||||
rlwinm r3, r3, 17, 31, 31
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm BOOL OSRestoreInterrupts(register BOOL status) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
cmpwi status, 0
|
||||
mfmsr r4
|
||||
beq disable
|
||||
|
||||
// Set external interrupts bit
|
||||
ori r5, r4, (1 << 15)
|
||||
b set_msr
|
||||
|
||||
disable:
|
||||
// Clear external interrupts bit
|
||||
rlwinm r5, r4, 0, 17, 15
|
||||
|
||||
set_msr:
|
||||
mtmsr r5
|
||||
// Return old interrupt status
|
||||
rlwinm r3, r4, 17, 31, 31
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static __OSInterruptHandler* InterruptHandlerTable;
|
||||
|
||||
__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt type, __OSInterruptHandler handler) {
|
||||
__OSInterruptHandler old = InterruptHandlerTable[type];
|
||||
InterruptHandlerTable[type] = handler;
|
||||
return old;
|
||||
}
|
||||
|
||||
__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt type) {
|
||||
return InterruptHandlerTable[type];
|
||||
}
|
||||
|
||||
void __OSInterruptInit(void) {
|
||||
InterruptHandlerTable = OSPhysicalToCached(0x3040);
|
||||
memset(InterruptHandlerTable, 0, 32 * 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, (OSExceptionHandler)ExternalInterruptHandler);
|
||||
}
|
||||
|
||||
u32 SetInterruptMask(OSInterruptMask mask, OSInterruptMask current) {
|
||||
u32 reg;
|
||||
|
||||
switch (__cntlzw(mask)) {
|
||||
case OS_INTR_MEM_0:
|
||||
case OS_INTR_MEM_1:
|
||||
case OS_INTR_MEM_2:
|
||||
case OS_INTR_MEM_3:
|
||||
case OS_INTR_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_INTR_DSP_AI:
|
||||
case OS_INTR_DSP_ARAM:
|
||||
case OS_INTR_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_INTR_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_INTR_EXI_0_EXI:
|
||||
case OS_INTR_EXI_0_TC:
|
||||
case OS_INTR_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_INTR_EXI_1_EXI:
|
||||
case OS_INTR_EXI_1_TC:
|
||||
case OS_INTR_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_INTR_EXI_2_EXI:
|
||||
case OS_INTR_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_INTR_PI_CP:
|
||||
case OS_INTR_PI_SI:
|
||||
case OS_INTR_PI_DI:
|
||||
case OS_INTR_PI_RSW:
|
||||
case OS_INTR_PI_ERROR:
|
||||
case OS_INTR_PI_VI:
|
||||
case OS_INTR_PI_DEBUG:
|
||||
case OS_INTR_PI_PE_TOKEN:
|
||||
case OS_INTR_PI_PE_FINISH:
|
||||
case OS_INTR_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;
|
||||
}
|
||||
|
||||
static u32 InterruptPrioTable[] = {
|
||||
0x00000100, 0x00000040, 0xF8000000, 0x00000200, 0x00000080, 0x00003000,
|
||||
0x00000020, 0x03FF8C00, 0x04000000, 0x00004000, 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
extern OSTime __OSLastInterruptTime;
|
||||
OSTime __OSLastInterruptTime;
|
||||
|
||||
extern s16 __OSLastInterrupt;
|
||||
s16 __OSLastInterrupt;
|
||||
|
||||
extern u32 __OSLastInterruptSrr0;
|
||||
u32 __OSLastInterruptSrr0;
|
||||
|
||||
void __OSDispatchInterrupt(__OSException exception, OSContext* context) {
|
||||
u32 intsr;
|
||||
u32 reg;
|
||||
OSInterruptMask cause;
|
||||
OSInterruptMask unmasked;
|
||||
OSInterruptMask* prio;
|
||||
__OSInterrupt interrupt;
|
||||
__OSInterruptHandler handler;
|
||||
intsr = __PIRegs[0];
|
||||
intsr &= ~0x00010000;
|
||||
|
||||
if (intsr == 0 || (intsr & __PIRegs[1]) == 0) {
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
cause = 0;
|
||||
|
||||
if (intsr & 0x00000080) {
|
||||
reg = __MEMRegs[15];
|
||||
if (reg & 0x1)
|
||||
cause |= OS_INTERRUPTMASK_MEM_0;
|
||||
if (reg & 0x2)
|
||||
cause |= OS_INTERRUPTMASK_MEM_1;
|
||||
if (reg & 0x4)
|
||||
cause |= OS_INTERRUPTMASK_MEM_2;
|
||||
if (reg & 0x8)
|
||||
cause |= OS_INTERRUPTMASK_MEM_3;
|
||||
if (reg & 0x10)
|
||||
cause |= OS_INTERRUPTMASK_MEM_ADDRESS;
|
||||
}
|
||||
|
||||
if (intsr & 0x00000040) {
|
||||
reg = __DSPRegs[5];
|
||||
if (reg & 0x8)
|
||||
cause |= OS_INTERRUPTMASK_DSP_AI;
|
||||
if (reg & 0x20)
|
||||
cause |= OS_INTERRUPTMASK_DSP_ARAM;
|
||||
if (reg & 0x80)
|
||||
cause |= OS_INTERRUPTMASK_DSP_DSP;
|
||||
}
|
||||
|
||||
if (intsr & 0x00000020) {
|
||||
reg = __AIRegs[0];
|
||||
if (reg & 0x8)
|
||||
cause |= OS_INTERRUPTMASK_AI_AI;
|
||||
}
|
||||
|
||||
if (intsr & 0x00000010) {
|
||||
reg = __EXIRegs[0];
|
||||
if (reg & 0x2)
|
||||
cause |= OS_INTERRUPTMASK_EXI_0_EXI;
|
||||
if (reg & 0x8)
|
||||
cause |= OS_INTERRUPTMASK_EXI_0_TC;
|
||||
if (reg & 0x800)
|
||||
cause |= OS_INTERRUPTMASK_EXI_0_EXT;
|
||||
reg = __EXIRegs[5];
|
||||
if (reg & 0x2)
|
||||
cause |= OS_INTERRUPTMASK_EXI_1_EXI;
|
||||
if (reg & 0x8)
|
||||
cause |= OS_INTERRUPTMASK_EXI_1_TC;
|
||||
if (reg & 0x800)
|
||||
cause |= OS_INTERRUPTMASK_EXI_1_EXT;
|
||||
reg = __EXIRegs[10];
|
||||
if (reg & 0x2)
|
||||
cause |= OS_INTERRUPTMASK_EXI_2_EXI;
|
||||
if (reg & 0x8)
|
||||
cause |= OS_INTERRUPTMASK_EXI_2_TC;
|
||||
}
|
||||
|
||||
if (intsr & 0x00002000)
|
||||
cause |= OS_INTERRUPTMASK_PI_HSP;
|
||||
if (intsr & 0x00001000)
|
||||
cause |= OS_INTERRUPTMASK_PI_DEBUG;
|
||||
if (intsr & 0x00000400)
|
||||
cause |= OS_INTERRUPTMASK_PI_PE_FINISH;
|
||||
if (intsr & 0x00000200)
|
||||
cause |= OS_INTERRUPTMASK_PI_PE_TOKEN;
|
||||
if (intsr & 0x00000100)
|
||||
cause |= OS_INTERRUPTMASK_PI_VI;
|
||||
if (intsr & 0x00000008)
|
||||
cause |= OS_INTERRUPTMASK_PI_SI;
|
||||
if (intsr & 0x00000004)
|
||||
cause |= OS_INTERRUPTMASK_PI_DI;
|
||||
if (intsr & 0x00000002)
|
||||
cause |= OS_INTERRUPTMASK_PI_RSW;
|
||||
if (intsr & 0x00000800)
|
||||
cause |= OS_INTERRUPTMASK_PI_CP;
|
||||
if (intsr & 0x00000001)
|
||||
cause |= OS_INTERRUPTMASK_PI_ERROR;
|
||||
|
||||
unmasked = cause & ~(*(OSInterruptMask*)OSPhysicalToCached(0x00C4) |
|
||||
*(OSInterruptMask*)OSPhysicalToCached(0x00C8));
|
||||
if (unmasked) {
|
||||
for (prio = InterruptPrioTable;; ++prio) {
|
||||
if (unmasked & *prio) {
|
||||
interrupt = (__OSInterrupt)__cntlzw(unmasked & *prio);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handler = __OSGetInterruptHandler(interrupt);
|
||||
if (handler) {
|
||||
if (OS_INTR_MEM_ADDRESS < interrupt) {
|
||||
__OSLastInterrupt = interrupt;
|
||||
__OSLastInterruptTime = OSGetTime();
|
||||
__OSLastInterruptSrr0 = context->srr0;
|
||||
}
|
||||
|
||||
OSDisableScheduler();
|
||||
handler(interrupt, context);
|
||||
OSEnableScheduler();
|
||||
__OSReschedule();
|
||||
OSLoadContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
static asm void ExternalInterruptHandler(register __OSInterrupt type, register OSContext* context) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
stw r0, context->gpr[0]
|
||||
stw r1, context->gpr[1]
|
||||
stw r2, context->gpr[2]
|
||||
stmw r6, context->gpr[6]
|
||||
|
||||
mfspr r0, GQR1
|
||||
stw r0, context->gqr[1]
|
||||
mfspr r0, GQR2
|
||||
stw r0, context->gqr[2]
|
||||
mfspr r0, GQR3
|
||||
stw r0, context->gqr[3]
|
||||
mfspr r0, GQR4
|
||||
stw r0, context->gqr[4]
|
||||
mfspr r0, GQR5
|
||||
stw r0, context->gqr[5]
|
||||
mfspr r0, GQR6
|
||||
stw r0, context->gqr[6]
|
||||
mfspr r0, GQR7
|
||||
stw r0, context->gqr[7]
|
||||
|
||||
stwu r1, -8(r1)
|
||||
b __OSDispatchInterrupt
|
||||
// clang-format on
|
||||
}
|
474
src/dolphin/os/OSLink.c
Normal file
474
src/dolphin/os/OSLink.c
Normal file
@ -0,0 +1,474 @@
|
||||
#include "dolphin/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 EnqueueTail(queue, moduleInfo, link) \
|
||||
do { \
|
||||
OSModuleInfo* __prev; \
|
||||
\
|
||||
__prev = (queue)->tail; \
|
||||
if (__prev == NULL) \
|
||||
(queue)->head = (moduleInfo); \
|
||||
else \
|
||||
__prev->link.next = (moduleInfo); \
|
||||
(moduleInfo)->link.prev = __prev; \
|
||||
(moduleInfo)->link.next = NULL; \
|
||||
(queue)->tail = (moduleInfo); \
|
||||
} while (0)
|
||||
|
||||
#define DequeueItem(queue, moduleInfo, link) \
|
||||
do { \
|
||||
OSModuleInfo* __next; \
|
||||
OSModuleInfo* __prev; \
|
||||
\
|
||||
__next = (moduleInfo)->link.next; \
|
||||
__prev = (moduleInfo)->link.prev; \
|
||||
\
|
||||
if (__next == NULL) \
|
||||
(queue)->tail = __prev; \
|
||||
else \
|
||||
__next->link.prev = __prev; \
|
||||
\
|
||||
if (__prev == NULL) \
|
||||
(queue)->head = __next; \
|
||||
else \
|
||||
__prev->link.next = __next; \
|
||||
} while (0)
|
||||
|
||||
OSModuleQueue __OSModuleInfoList : (OS_BASE_CACHED | 0x30C8);
|
||||
|
||||
#pragma dont_inline on
|
||||
|
||||
__declspec(weak) void OSNotifyLink(OSModuleInfo* module) {}
|
||||
__declspec(weak) void OSNotifyUnlink(OSModuleInfo* module) {}
|
||||
|
||||
#pragma dont_inline reset
|
||||
|
||||
void OSSetStringTable(void* string_table) {
|
||||
__OSStringTable = string_table;
|
||||
}
|
||||
|
||||
static BOOL Relocate(OSModuleHeader* newModule, OSModuleHeader* module) {
|
||||
OSModuleID idNew;
|
||||
OSImportInfo* imp;
|
||||
OSRel* rel;
|
||||
OSSectionInfo* si;
|
||||
OSSectionInfo* siFlush;
|
||||
u32* p;
|
||||
u32 offset;
|
||||
u32 x;
|
||||
|
||||
idNew = newModule ? newModule->info.id : 0;
|
||||
for (imp = (OSImportInfo*)module->impOffset;
|
||||
imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++)
|
||||
{
|
||||
if (imp->id == idNew) {
|
||||
goto Found;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
Found:
|
||||
siFlush = 0;
|
||||
for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) {
|
||||
(u8*)p += rel->offset;
|
||||
if (idNew) {
|
||||
si = &OSGetSectionInfo(newModule)[rel->section];
|
||||
offset = OS_SECTIONINFO_OFFSET(si->offset);
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
switch (rel->type) {
|
||||
case R_PPC_NONE:
|
||||
break;
|
||||
case R_PPC_ADDR32:
|
||||
x = offset + rel->addend;
|
||||
*p = x;
|
||||
break;
|
||||
case R_PPC_ADDR24:
|
||||
x = offset + rel->addend;
|
||||
*p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
|
||||
break;
|
||||
case R_PPC_ADDR16:
|
||||
x = offset + rel->addend;
|
||||
*(u16*)p = (u16)(x & 0xffff);
|
||||
break;
|
||||
case R_PPC_ADDR16_LO:
|
||||
x = offset + rel->addend;
|
||||
*(u16*)p = (u16)(x & 0xffff);
|
||||
break;
|
||||
case R_PPC_ADDR16_HI:
|
||||
x = offset + rel->addend;
|
||||
*(u16*)p = (u16)(((x >> 16) & 0xffff));
|
||||
break;
|
||||
case R_PPC_ADDR16_HA:
|
||||
x = offset + rel->addend;
|
||||
*(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff);
|
||||
break;
|
||||
case R_PPC_ADDR14:
|
||||
case R_PPC_ADDR14_BRTAKEN:
|
||||
case R_PPC_ADDR14_BRNTAKEN:
|
||||
x = offset + rel->addend;
|
||||
*p = (*p & ~0x0000fffc) | (x & 0x0000fffc);
|
||||
break;
|
||||
case R_PPC_REL24:
|
||||
x = offset + rel->addend - (u32)p;
|
||||
*p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
|
||||
break;
|
||||
case R_PPC_REL14:
|
||||
case R_PPC_REL14_BRTAKEN:
|
||||
case R_PPC_REL14_BRNTAKEN:
|
||||
x = offset + rel->addend - (u32)p;
|
||||
*p = (*p & ~0x0000fffc) | (x & 0x0000fffc);
|
||||
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;
|
||||
}
|
||||
|
||||
static BOOL Link(OSModuleInfo* newModule, void* bss, BOOL fixed) {
|
||||
u32 i;
|
||||
OSSectionInfo* si;
|
||||
OSModuleHeader* moduleHeader;
|
||||
OSModuleInfo* moduleInfo;
|
||||
OSImportInfo* imp;
|
||||
|
||||
moduleHeader = (OSModuleHeader*)newModule;
|
||||
moduleHeader->bssSection = 0;
|
||||
|
||||
if (OS_MODULE_VERSION < newModule->version ||
|
||||
2 <= newModule->version &&
|
||||
(moduleHeader->align && (u32)newModule % moduleHeader->align != 0 ||
|
||||
moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
EnqueueTail(&__OSModuleInfoList, newModule, link);
|
||||
newModule->sectionInfoOffset += (u32)moduleHeader;
|
||||
moduleHeader->relOffset += (u32)moduleHeader;
|
||||
moduleHeader->impOffset += (u32)moduleHeader;
|
||||
if (3 <= newModule->version) {
|
||||
moduleHeader->fixSize += (u32)moduleHeader;
|
||||
}
|
||||
|
||||
for (i = 1; i < newModule->numSections; i++) {
|
||||
si = &OSGetSectionInfo(newModule)[i];
|
||||
if (si->offset != 0) {
|
||||
si->offset += (u32)moduleHeader;
|
||||
} else if (si->size != 0) {
|
||||
moduleHeader->bssSection = (u8)i;
|
||||
si->offset = (u32)bss;
|
||||
}
|
||||
}
|
||||
|
||||
for (imp = (OSImportInfo*)moduleHeader->impOffset;
|
||||
imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++)
|
||||
{
|
||||
imp->offset += (u32)moduleHeader;
|
||||
}
|
||||
|
||||
if (moduleHeader->prologSection != SHN_UNDEF) {
|
||||
moduleHeader->prolog +=
|
||||
OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->prologSection].offset);
|
||||
}
|
||||
|
||||
if (moduleHeader->epilogSection != SHN_UNDEF) {
|
||||
moduleHeader->epilog +=
|
||||
OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->epilogSection].offset);
|
||||
}
|
||||
|
||||
if (moduleHeader->unresolvedSection != SHN_UNDEF) {
|
||||
moduleHeader->unresolved += OS_SECTIONINFO_OFFSET(
|
||||
OSGetSectionInfo(newModule)[moduleHeader->unresolvedSection].offset);
|
||||
}
|
||||
|
||||
if (__OSStringTable) {
|
||||
newModule->nameOffset += (u32)__OSStringTable;
|
||||
}
|
||||
|
||||
Relocate(0, moduleHeader);
|
||||
|
||||
for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
|
||||
Relocate(moduleHeader, (OSModuleHeader*)moduleInfo);
|
||||
if (moduleInfo != newModule) {
|
||||
Relocate((OSModuleHeader*)moduleInfo, moduleHeader);
|
||||
}
|
||||
}
|
||||
|
||||
if (fixed) {
|
||||
for (imp = (OSImportInfo*)moduleHeader->impOffset;
|
||||
imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++)
|
||||
{
|
||||
if (imp->id == 0 || imp->id == newModule->id) {
|
||||
moduleHeader->impSize = (u32)((u8*)imp - (u8*)moduleHeader->impOffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(bss, 0, moduleHeader->bssSize);
|
||||
|
||||
OSNotifyLink(newModule);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL OSLink(OSModuleInfo* newModule, void* bss) {
|
||||
return Link(newModule, bss, FALSE);
|
||||
}
|
||||
|
||||
BOOL OSLinkFixed(OSModuleInfo* newModule, void* bss) {
|
||||
if (OS_MODULE_VERSION < newModule->version || newModule->version < 3) {
|
||||
return FALSE;
|
||||
}
|
||||
return Link(newModule, bss, TRUE);
|
||||
}
|
||||
|
||||
static BOOL Undo(OSModuleHeader* newModule, OSModuleHeader* module) {
|
||||
OSModuleID idNew;
|
||||
OSImportInfo* imp;
|
||||
OSRel* rel;
|
||||
OSSectionInfo* si;
|
||||
OSSectionInfo* siFlush;
|
||||
u32* p;
|
||||
u32 offset;
|
||||
u32 x;
|
||||
|
||||
idNew = newModule->info.id;
|
||||
for (imp = (OSImportInfo*)module->impOffset;
|
||||
imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++)
|
||||
{
|
||||
if (imp->id == idNew) {
|
||||
goto Found;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
Found:
|
||||
siFlush = 0;
|
||||
for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) {
|
||||
(u8*)p += rel->offset;
|
||||
si = &OSGetSectionInfo(newModule)[rel->section];
|
||||
offset = OS_SECTIONINFO_OFFSET(si->offset);
|
||||
x = 0;
|
||||
switch (rel->type) {
|
||||
case R_PPC_NONE:
|
||||
break;
|
||||
case R_PPC_ADDR32:
|
||||
*p = x;
|
||||
break;
|
||||
case R_PPC_ADDR24:
|
||||
*p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
|
||||
break;
|
||||
case R_PPC_ADDR16:
|
||||
*(u16*)p = (u16)(x & 0xffff);
|
||||
break;
|
||||
case R_PPC_ADDR16_LO:
|
||||
*(u16*)p = (u16)(x & 0xffff);
|
||||
break;
|
||||
case R_PPC_ADDR16_HI:
|
||||
*(u16*)p = (u16)(((x >> 16) & 0xffff));
|
||||
break;
|
||||
case R_PPC_ADDR16_HA:
|
||||
*(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff);
|
||||
break;
|
||||
case R_PPC_ADDR14:
|
||||
case R_PPC_ADDR14_BRTAKEN:
|
||||
case R_PPC_ADDR14_BRNTAKEN:
|
||||
*p = (*p & ~0x0000fffc) | (x & 0x0000fffc);
|
||||
break;
|
||||
case R_PPC_REL24:
|
||||
if (module->unresolvedSection != SHN_UNDEF) {
|
||||
x = (u32)module->unresolved - (u32)p;
|
||||
}
|
||||
*p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
|
||||
break;
|
||||
case R_PPC_REL14:
|
||||
case R_PPC_REL14_BRTAKEN:
|
||||
case R_PPC_REL14_BRNTAKEN:
|
||||
*p = (*p & ~0x0000fffc) | (x & 0x0000fffc);
|
||||
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;
|
||||
OSSectionInfo* si;
|
||||
OSImportInfo* imp;
|
||||
|
||||
moduleHeader = (OSModuleHeader*)oldModule;
|
||||
|
||||
DequeueItem(&__OSModuleInfoList, oldModule, link);
|
||||
|
||||
for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
|
||||
Undo(moduleHeader, (OSModuleHeader*)moduleInfo);
|
||||
}
|
||||
|
||||
OSNotifyUnlink(oldModule);
|
||||
|
||||
if (__OSStringTable) {
|
||||
oldModule->nameOffset -= (u32)__OSStringTable;
|
||||
}
|
||||
|
||||
if (moduleHeader->prologSection != SHN_UNDEF) {
|
||||
moduleHeader->prolog -=
|
||||
OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->prologSection].offset);
|
||||
}
|
||||
|
||||
if (moduleHeader->epilogSection != SHN_UNDEF) {
|
||||
moduleHeader->epilog -=
|
||||
OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->epilogSection].offset);
|
||||
}
|
||||
|
||||
if (moduleHeader->unresolvedSection != SHN_UNDEF) {
|
||||
moduleHeader->unresolved -= OS_SECTIONINFO_OFFSET(
|
||||
OSGetSectionInfo(oldModule)[moduleHeader->unresolvedSection].offset);
|
||||
}
|
||||
|
||||
for (imp = (OSImportInfo*)moduleHeader->impOffset;
|
||||
imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++)
|
||||
{
|
||||
imp->offset -= (u32)moduleHeader;
|
||||
}
|
||||
|
||||
for (i = 1; i < oldModule->numSections; i++) {
|
||||
si = &OSGetSectionInfo(oldModule)[i];
|
||||
if (i == moduleHeader->bssSection) {
|
||||
moduleHeader->bssSection = 0;
|
||||
si->offset = 0;
|
||||
} else if (si->offset != 0) {
|
||||
si->offset -= (u32)moduleHeader;
|
||||
}
|
||||
}
|
||||
moduleHeader->relOffset -= (u32)moduleHeader;
|
||||
moduleHeader->impOffset -= (u32)moduleHeader;
|
||||
oldModule->sectionInfoOffset -= (u32)moduleHeader;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void __OSModuleInit(void) {
|
||||
__OSModuleList.tail = NULL;
|
||||
__OSModuleList.head = NULL;
|
||||
__OSStringTable = NULL;
|
||||
}
|
210
src/dolphin/os/OSMemory.c
Normal file
210
src/dolphin/os/OSMemory.c
Normal file
@ -0,0 +1,210 @@
|
||||
#include "dolphin/os/OSMemory.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
#define TRUNC(n, a) (((u32)(n)) & ~((a)-1))
|
||||
#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1))
|
||||
|
||||
vu16 __MEMRegs[64] : 0xCC004000;
|
||||
|
||||
extern OSErrorHandlerEx __OSErrorTable[16];
|
||||
|
||||
static BOOL OnReset(BOOL final) {
|
||||
if (final != FALSE) {
|
||||
__MEMRegs[8] = 0xFF;
|
||||
__OSMaskInterrupts(OS_INTERRUPTMASK_MEM_RESET);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext* context) {
|
||||
u32 addr;
|
||||
u32 cause;
|
||||
|
||||
cause = __MEMRegs[0xf];
|
||||
addr = (((u32)__MEMRegs[0x12] & 0x3ff) << 16) | __MEMRegs[0x11];
|
||||
__MEMRegs[0x10] = 0;
|
||||
|
||||
if (__OSErrorTable[EXCEPTION_MEMORY_PROTECTION]) {
|
||||
__OSErrorTable[EXCEPTION_MEMORY_PROTECTION](EXCEPTION_MEMORY_PROTECTION, context, cause,
|
||||
addr);
|
||||
return;
|
||||
}
|
||||
|
||||
__OSUnhandledException(EXCEPTION_MEMORY_PROTECTION, context, cause, addr);
|
||||
}
|
||||
|
||||
void OSProtectRange(u32 chan, void* addr, u32 nBytes, u32 control) {
|
||||
BOOL enabled;
|
||||
u32 start;
|
||||
u32 end;
|
||||
u16 reg;
|
||||
if (4 <= chan) {
|
||||
return;
|
||||
}
|
||||
|
||||
control &= OS_PROTECT_CONTROL_RDWR;
|
||||
|
||||
end = (u32)addr + nBytes;
|
||||
start = TRUNC(addr, 1u << 10);
|
||||
end = ROUND(end, 1u << 10);
|
||||
|
||||
DCFlushRange((void*)start, end - start);
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
__OSMaskInterrupts(OS_INTERRUPTMASK(OS_INTR_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_INTR_MEM_0 + chan));
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
static asm void Config24MB(void) {
|
||||
// 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
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static asm void Config48MB(void) {
|
||||
// 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
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static asm void RealMode(register u32 config) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
clrlwi config, config, 2
|
||||
mtspr 0x1a, config
|
||||
mfmsr config
|
||||
rlwinm config, config, 0, 0x1c, 0x19
|
||||
mtspr 0x1b, config
|
||||
rfi
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static OSResetFunctionInfo ResetFunctionInfo = {
|
||||
OnReset,
|
||||
0x7F,
|
||||
};
|
||||
|
||||
inline u32 OSGetPhysicalMemSize() {
|
||||
return *(u32*)(OSPhysicalToCached(0x0028));
|
||||
}
|
||||
|
||||
inline u32 OSGetConsoleSimulatedMemSize() {
|
||||
return *(u32*)(OSPhysicalToCached(0x00F0));
|
||||
}
|
||||
|
||||
void __OSInitMemoryProtection() {
|
||||
u32 padding[8];
|
||||
u32 simulatedSize;
|
||||
BOOL enabled;
|
||||
simulatedSize = OSGetConsoleSimulatedMemSize();
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
__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_INTR_MEM_0, MEMIntrruptHandler);
|
||||
__OSSetInterruptHandler(OS_INTR_MEM_1, MEMIntrruptHandler);
|
||||
__OSSetInterruptHandler(OS_INTR_MEM_2, MEMIntrruptHandler);
|
||||
__OSSetInterruptHandler(OS_INTR_MEM_3, MEMIntrruptHandler);
|
||||
__OSSetInterruptHandler(OS_INTR_MEM_ADDRESS, MEMIntrruptHandler);
|
||||
OSRegisterResetFunction(&ResetFunctionInfo);
|
||||
|
||||
if (OSGetConsoleSimulatedMemSize() < OSGetPhysicalMemSize() &&
|
||||
OSGetConsoleSimulatedMemSize() == 0x1800000)
|
||||
{
|
||||
DCInvalidateRange((void*)0x81800000, 0x1800000);
|
||||
__MEMRegs[20] = 2;
|
||||
}
|
||||
|
||||
if (simulatedSize <= 0x1800000) {
|
||||
RealMode((u32)&Config24MB);
|
||||
} else if (simulatedSize <= 0x3000000) {
|
||||
RealMode((u32)&Config48MB);
|
||||
}
|
||||
|
||||
__OSUnmaskInterrupts(OS_INTERRUPTMASK_MEM_ADDRESS);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
87
src/dolphin/os/OSMessage.c
Normal file
87
src/dolphin/os/OSMessage.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include "dolphin/os/OSMessage.h"
|
||||
|
||||
void OSInitMessageQueue(OSMessageQueue* mq, OSMessage* msgArray, s32 msgCount) {
|
||||
OSInitThreadQueue(&mq->sending_queue);
|
||||
OSInitThreadQueue(&mq->receiving_queue);
|
||||
mq->message_array = msgArray;
|
||||
mq->num_messages = msgCount;
|
||||
mq->first_index = 0;
|
||||
mq->num_used = 0;
|
||||
}
|
||||
|
||||
BOOL OSSendMessage(OSMessageQueue* mq, OSMessage msg, s32 flags) {
|
||||
BOOL enabled;
|
||||
s32 lastIndex;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
while (mq->num_messages <= mq->num_used) {
|
||||
if (!(flags & OS_MESSAGE_BLOCK)) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return FALSE;
|
||||
} else {
|
||||
OSSleepThread(&mq->sending_queue);
|
||||
}
|
||||
}
|
||||
|
||||
lastIndex = (mq->first_index + mq->num_used) % mq->num_messages;
|
||||
mq->message_array[lastIndex] = msg;
|
||||
mq->num_used++;
|
||||
|
||||
OSWakeupThread(&mq->receiving_queue);
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL OSReceiveMessage(OSMessageQueue* mq, OSMessage* msg, s32 flags) {
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
while (mq->num_used == 0) {
|
||||
if (!(flags & OS_MESSAGE_BLOCK)) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return FALSE;
|
||||
} else {
|
||||
OSSleepThread(&mq->receiving_queue);
|
||||
}
|
||||
}
|
||||
|
||||
if (msg != NULL) {
|
||||
*msg = mq->message_array[mq->first_index];
|
||||
}
|
||||
mq->first_index = (mq->first_index + 1) % mq->num_messages;
|
||||
mq->num_used--;
|
||||
|
||||
OSWakeupThread(&mq->sending_queue);
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL OSJamMessage(OSMessageQueue* queue, void* msg, s32 flags) {
|
||||
s32 lastMesg;
|
||||
u32 interrupt;
|
||||
|
||||
interrupt = OSDisableInterrupts();
|
||||
|
||||
while (queue->num_messages <= queue->num_used) {
|
||||
if (!(flags & OS_MSG_PERSISTENT)) {
|
||||
OSRestoreInterrupts(interrupt);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
OSSleepThread(&queue->sending_queue);
|
||||
}
|
||||
|
||||
// Find last position in queue
|
||||
lastMesg = (queue->first_index + queue->num_messages - 1) % queue->num_messages;
|
||||
queue->first_index = lastMesg;
|
||||
queue->message_array[queue->first_index] = msg;
|
||||
queue->num_used++;
|
||||
|
||||
OSWakeupThread(&queue->receiving_queue);
|
||||
OSRestoreInterrupts(interrupt);
|
||||
return TRUE;
|
||||
}
|
231
src/dolphin/os/OSMutex.c
Normal file
231
src/dolphin/os/OSMutex.c
Normal file
@ -0,0 +1,231 @@
|
||||
#include "dolphin/os/OSMutex.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
#define PushTail(queue, mutex, link) \
|
||||
do { \
|
||||
OSMutex* __prev; \
|
||||
\
|
||||
__prev = (queue)->tail; \
|
||||
if (__prev == NULL) \
|
||||
(queue)->head = (mutex); \
|
||||
else \
|
||||
__prev->link.next = (mutex); \
|
||||
(mutex)->link.prev = __prev; \
|
||||
(mutex)->link.next = NULL; \
|
||||
(queue)->tail = (mutex); \
|
||||
} while (0)
|
||||
|
||||
#define PopHead(queue, mutex, link) \
|
||||
do { \
|
||||
OSMutex* __next; \
|
||||
\
|
||||
(mutex) = (queue)->head; \
|
||||
__next = (mutex)->link.next; \
|
||||
if (__next == NULL) \
|
||||
(queue)->tail = NULL; \
|
||||
else \
|
||||
__next->link.prev = NULL; \
|
||||
(queue)->head = __next; \
|
||||
} while (0)
|
||||
|
||||
#define PopItem(queue, mutex, link) \
|
||||
do { \
|
||||
OSMutex* __next; \
|
||||
OSMutex* __prev; \
|
||||
\
|
||||
__next = (mutex)->link.next; \
|
||||
__prev = (mutex)->link.prev; \
|
||||
\
|
||||
if (__next == NULL) \
|
||||
(queue)->tail = __prev; \
|
||||
else \
|
||||
__next->link.prev = __prev; \
|
||||
\
|
||||
if (__prev == NULL) \
|
||||
(queue)->head = __next; \
|
||||
else \
|
||||
__prev->link.next = __next; \
|
||||
} while (0)
|
||||
|
||||
//
|
||||
// Declarations:
|
||||
//
|
||||
|
||||
void OSInitMutex(OSMutex* mutex) {
|
||||
OSInitThreadQueue(&mutex->queue);
|
||||
mutex->thread = 0;
|
||||
mutex->count = 0;
|
||||
}
|
||||
|
||||
void OSLockMutex(OSMutex* mutex) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
OSThread* ownerThread;
|
||||
|
||||
while (TRUE) {
|
||||
ownerThread = ((OSMutex*)mutex)->thread;
|
||||
if (ownerThread == 0) {
|
||||
mutex->thread = currentThread;
|
||||
mutex->count++;
|
||||
PushTail(¤tThread->owned_mutexes, mutex, link);
|
||||
break;
|
||||
} else if (ownerThread == currentThread) {
|
||||
mutex->count++;
|
||||
break;
|
||||
} else {
|
||||
currentThread->mutex = mutex;
|
||||
__OSPromoteThread(mutex->thread, currentThread->effective_priority);
|
||||
OSSleepThread(&mutex->queue);
|
||||
currentThread->mutex = 0;
|
||||
}
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSUnlockMutex(OSMutex* mutex) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
if (mutex->thread == currentThread && --mutex->count == 0) {
|
||||
PopItem(¤tThread->owned_mutexes, mutex, link);
|
||||
mutex->thread = NULL;
|
||||
if ((s32)currentThread->effective_priority < (s32)currentThread->base_priority) {
|
||||
currentThread->effective_priority = __OSGetEffectivePriority(currentThread);
|
||||
}
|
||||
|
||||
OSWakeupThread(&mutex->queue);
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void __OSUnlockAllMutex(OSThread* thread) {
|
||||
OSMutex* mutex;
|
||||
|
||||
while (thread->owned_mutexes.head) {
|
||||
PopHead(&thread->owned_mutexes, mutex, link);
|
||||
mutex->count = 0;
|
||||
mutex->thread = NULL;
|
||||
OSWakeupThread(&mutex->queue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL OSTryLockMutex(OSMutex* mutex) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
BOOL locked;
|
||||
if (mutex->thread == 0) {
|
||||
mutex->thread = currentThread;
|
||||
mutex->count++;
|
||||
PushTail(¤tThread->owned_mutexes, mutex, link);
|
||||
locked = TRUE;
|
||||
} else if (mutex->thread == currentThread) {
|
||||
mutex->count++;
|
||||
locked = TRUE;
|
||||
} else {
|
||||
locked = FALSE;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return locked;
|
||||
}
|
||||
|
||||
void OSInitCond(OSCond* cond) { OSInitThreadQueue(&cond->queue); }
|
||||
|
||||
void OSWaitCond(OSCond* cond, OSMutex* mutex) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
s32 count;
|
||||
|
||||
if (mutex->thread == currentThread) {
|
||||
count = mutex->count;
|
||||
mutex->count = 0;
|
||||
PopItem(¤tThread->owned_mutexes, mutex, link);
|
||||
mutex->thread = NULL;
|
||||
|
||||
if (currentThread->effective_priority < (s32)currentThread->base_priority) {
|
||||
currentThread->effective_priority = __OSGetEffectivePriority(currentThread);
|
||||
}
|
||||
|
||||
OSDisableScheduler();
|
||||
OSWakeupThread(&mutex->queue);
|
||||
OSEnableScheduler();
|
||||
OSSleepThread(&cond->queue);
|
||||
OSLockMutex(mutex);
|
||||
mutex->count = count;
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSSignalCond(OSCond* cond) {
|
||||
OSWakeupThread(&cond->queue);
|
||||
}
|
||||
|
||||
static BOOL IsMember(OSMutexQueue* queue, OSMutex* mutex) {
|
||||
OSMutex* member;
|
||||
|
||||
for (member = queue->head; member; member = member->link.next) {
|
||||
if (mutex == member)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL __OSCheckMutex(OSMutex* mutex) {
|
||||
OSThread* thread;
|
||||
OSThreadQueue* queue;
|
||||
OSPriority priority = 0;
|
||||
|
||||
queue = &mutex->queue;
|
||||
if (!(queue->head == NULL || queue->head->link.prev == NULL))
|
||||
return FALSE;
|
||||
if (!(queue->tail == NULL || queue->tail->link.next == NULL))
|
||||
return FALSE;
|
||||
for (thread = queue->head; thread; thread = thread->link.next) {
|
||||
if (!(thread->link.next == NULL || thread == thread->link.next->link.prev))
|
||||
return FALSE;
|
||||
if (!(thread->link.prev == NULL || thread == thread->link.prev->link.next))
|
||||
return FALSE;
|
||||
|
||||
if (thread->state != OS_THREAD_STATE_WAITING)
|
||||
return FALSE;
|
||||
|
||||
if (thread->effective_priority < priority)
|
||||
return FALSE;
|
||||
priority = thread->effective_priority;
|
||||
}
|
||||
|
||||
if (mutex->thread) {
|
||||
if (mutex->count <= 0)
|
||||
return FALSE;
|
||||
} else {
|
||||
if (0 != mutex->count)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL __OSCheckDeadLock(OSThread* thread) {
|
||||
OSMutex* mutex;
|
||||
|
||||
mutex = thread->mutex;
|
||||
while (mutex && mutex->thread) {
|
||||
if (mutex->thread == thread)
|
||||
return TRUE;
|
||||
mutex = mutex->thread->mutex;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL __OSCheckMutexes(OSThread* thread) {
|
||||
OSMutex* mutex;
|
||||
|
||||
for (mutex = thread->owned_mutexes.head; mutex; mutex = mutex->link.next) {
|
||||
if (mutex->thread != thread)
|
||||
return FALSE;
|
||||
if (!__OSCheckMutex(mutex))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
29
src/dolphin/os/OSReboot.c
Normal file
29
src/dolphin/os/OSReboot.c
Normal file
@ -0,0 +1,29 @@
|
||||
#include "dolphin/os/OSReboot.h"
|
||||
#include "dolphin/os/OSContext.h"
|
||||
#include "dolphin/os/OSExec.h"
|
||||
|
||||
void __OSReboot(u32 resetCode, u32 bootDol) {
|
||||
struct OSContext context;
|
||||
char* iVar1;
|
||||
OSDisableInterrupts();
|
||||
OSSetArenaLo((void*)0x81280000);
|
||||
OSSetArenaHi((void*)0x812f0000);
|
||||
OSClearContext(&context);
|
||||
OSSetCurrentContext(&context);
|
||||
iVar1 = NULL;
|
||||
__OSBootDol(bootDol, resetCode | 0x80000000, &iVar1);
|
||||
}
|
||||
|
||||
static void* SaveStart;
|
||||
|
||||
static void* SaveEnd;
|
||||
|
||||
void OSSetSaveRegion(void* start, void* end) {
|
||||
SaveStart = start;
|
||||
SaveEnd = end;
|
||||
}
|
||||
|
||||
void OSGetSaveRegion(void** start, void** end) {
|
||||
*start = SaveStart;
|
||||
*end = SaveEnd;
|
||||
}
|
210
src/dolphin/os/OSReset.c
Normal file
210
src/dolphin/os/OSReset.c
Normal file
@ -0,0 +1,210 @@
|
||||
#include "dolphin/os/OSReset.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
vu16 __VIRegs[59] : 0xCC002000;
|
||||
OSThreadQueue __OSActiveThreadQueue : (OS_BASE_CACHED | 0x00DC);
|
||||
|
||||
extern OSExecParams __OSRebootParams;
|
||||
|
||||
static OSResetQueue ResetFunctionQueue;
|
||||
|
||||
void OSRegisterResetFunction(OSResetFunctionInfo* func) {
|
||||
OSResetFunctionInfo* tmp;
|
||||
OSResetFunctionInfo* iter;
|
||||
|
||||
for (iter = ResetFunctionQueue.first; iter && iter->priority <= func->priority;
|
||||
iter = iter->next)
|
||||
;
|
||||
|
||||
if (iter == NULL) {
|
||||
tmp = ResetFunctionQueue.last;
|
||||
if (tmp == NULL) {
|
||||
ResetFunctionQueue.first = func;
|
||||
} else {
|
||||
tmp->next = func;
|
||||
}
|
||||
func->prev = tmp;
|
||||
func->next = NULL;
|
||||
ResetFunctionQueue.last = func;
|
||||
return;
|
||||
}
|
||||
|
||||
func->next = iter;
|
||||
tmp = iter->prev;
|
||||
iter->prev = func;
|
||||
func->prev = tmp;
|
||||
if (tmp == NULL) {
|
||||
ResetFunctionQueue.first = func;
|
||||
return;
|
||||
}
|
||||
tmp->next = func;
|
||||
}
|
||||
|
||||
BOOL __OSCallResetFunctions(u32 arg0) {
|
||||
OSResetFunctionInfo* iter;
|
||||
s32 retCode = 0;
|
||||
u32 priority = 0;
|
||||
s32 temp;
|
||||
|
||||
for (iter = ResetFunctionQueue.first; iter != NULL;) {
|
||||
if (retCode != 0 && priority != iter->priority)
|
||||
break;
|
||||
temp = !iter->func(arg0);
|
||||
priority = iter->priority;
|
||||
iter = iter->next;
|
||||
retCode |= temp;
|
||||
}
|
||||
retCode |= !__OSSyncSram();
|
||||
if (retCode) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static asm void Reset(register s32 param_0) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
b lbl_8033F7AC
|
||||
|
||||
lbl_8033F790:
|
||||
mfspr r8, 0x3f0
|
||||
ori r8, r8, 8
|
||||
mtspr 0x3f0, r8
|
||||
isync
|
||||
sync
|
||||
nop
|
||||
b lbl_8033F7B0
|
||||
|
||||
lbl_8033F7AC:
|
||||
b lbl_8033F7CC
|
||||
|
||||
lbl_8033F7B0:
|
||||
mftb r5, 0x10c
|
||||
|
||||
lbl_8033F7B4:
|
||||
mftb r6, 0x10c
|
||||
subf r7, r5, r6
|
||||
cmplwi r7, 0x1124
|
||||
blt lbl_8033F7B4
|
||||
nop
|
||||
b lbl_8033F7D0
|
||||
|
||||
lbl_8033F7CC:
|
||||
b lbl_8033F7EC
|
||||
|
||||
lbl_8033F7D0:
|
||||
lis r8, 0xCC00
|
||||
ori r8, r8, 0x3000
|
||||
li r4, 3
|
||||
stw r4, 0x24(r8)
|
||||
stw param_0, 0x24(r8)
|
||||
nop
|
||||
b lbl_8033F7F0
|
||||
|
||||
lbl_8033F7EC:
|
||||
b lbl_8033F7F8
|
||||
|
||||
lbl_8033F7F0:
|
||||
nop
|
||||
b lbl_8033F7F0
|
||||
|
||||
lbl_8033F7F8:
|
||||
b lbl_8033F790
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
#pragma dont_inline on
|
||||
static void KillThreads(void) {
|
||||
OSThread* thread;
|
||||
OSThread* next;
|
||||
|
||||
for (thread = __OSActiveThreadQueue.head; thread; thread = next) {
|
||||
next = thread->active_threads_link.next;
|
||||
switch (thread->state) {
|
||||
case 1:
|
||||
case 4:
|
||||
OSCancelThread(thread);
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma dont_inline reset
|
||||
|
||||
void __OSDoHotReset(s32 arg0) {
|
||||
OSDisableInterrupts();
|
||||
__VIRegs[1] = 0;
|
||||
ICFlashInvalidate();
|
||||
Reset(arg0 * 8);
|
||||
}
|
||||
|
||||
static u32 bootThisDol;
|
||||
|
||||
void OSResetSystem(int reset, u32 resetCode, BOOL forceMenu) {
|
||||
BOOL rc;
|
||||
BOOL disableRecalibration;
|
||||
u32 unk;
|
||||
OSDisableScheduler();
|
||||
|
||||
if (reset == OS_RESET_HOTRESET && forceMenu) {
|
||||
OSSram* sram;
|
||||
|
||||
sram = __OSLockSram();
|
||||
sram->flags |= 0x40;
|
||||
__OSUnlockSram(TRUE);
|
||||
|
||||
resetCode = 0;
|
||||
}
|
||||
|
||||
if (reset == OS_RESET_SHUTDOWN ||
|
||||
(reset == OS_RESET_RESTART && (bootThisDol || resetCode + 0x3fff0000 == 0)))
|
||||
{
|
||||
__OSStopAudioSystem();
|
||||
disableRecalibration = __PADDisableRecalibration(TRUE);
|
||||
while (!__OSCallResetFunctions(FALSE))
|
||||
;
|
||||
while (!__OSSyncSram())
|
||||
;
|
||||
OSDisableInterrupts();
|
||||
__OSCallResetFunctions(TRUE);
|
||||
LCDisable();
|
||||
__PADDisableRecalibration(disableRecalibration);
|
||||
KillThreads();
|
||||
} else {
|
||||
__OSStopAudioSystem();
|
||||
while (!__OSCallResetFunctions(FALSE))
|
||||
;
|
||||
while (!__OSSyncSram())
|
||||
;
|
||||
OSDisableInterrupts();
|
||||
__OSCallResetFunctions(TRUE);
|
||||
LCDisable();
|
||||
KillThreads();
|
||||
}
|
||||
|
||||
if (reset == OS_RESET_HOTRESET) {
|
||||
__OSDoHotReset(resetCode);
|
||||
} else if (reset == OS_RESET_RESTART) {
|
||||
if (forceMenu == TRUE) {
|
||||
OSReport(
|
||||
"OSResetSystem(): You can't specify TRUE to forceMenu if you restart. Ignored\n");
|
||||
}
|
||||
OSEnableScheduler();
|
||||
__OSReboot(resetCode, bootThisDol);
|
||||
}
|
||||
memset(OSPhysicalToCached(0x40), 0, 0xcc - 0x40);
|
||||
memset(OSPhysicalToCached(0xd4), 0, 0xe8 - 0xd4);
|
||||
memset(OSPhysicalToCached(0xf4), 0, 0xf8 - 0xf4);
|
||||
memset(OSPhysicalToCached(0x3000), 0, 0xc0);
|
||||
memset(OSPhysicalToCached(0x30c8), 0, 0xd4 - 0xc8);
|
||||
memset(OSPhysicalToCached(0x30e2), 0, 1);
|
||||
}
|
||||
|
||||
u32 OSGetResetCode(void) {
|
||||
if (__OSRebootParams.valid)
|
||||
return 0x80000000 | __OSRebootParams.restartCode;
|
||||
|
||||
return ((__PIRegs[9] & ~7) >> 3);
|
||||
}
|
92
src/dolphin/os/OSResetSW.c
Normal file
92
src/dolphin/os/OSResetSW.c
Normal file
@ -0,0 +1,92 @@
|
||||
#include "dolphin/os/OSResetSW.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
#include "dolphin/os/OSReset.h"
|
||||
|
||||
u8 GameChoice : (OS_BASE_CACHED | 0x30E3);
|
||||
|
||||
void __OSResetSWInterruptHandler(__OSInterrupt interrupt, OSContext* context);
|
||||
|
||||
static OSResetCallback ResetCallback;
|
||||
|
||||
static BOOL Down;
|
||||
|
||||
static BOOL LastState;
|
||||
|
||||
static OSTime HoldUp;
|
||||
|
||||
static OSTime HoldDown;
|
||||
|
||||
void __OSResetSWInterruptHandler(__OSInterrupt interrupt, OSContext* context) {
|
||||
OSResetCallback callback;
|
||||
|
||||
HoldDown = __OSGetSystemTime();
|
||||
while (__OSGetSystemTime() - HoldDown < OSMicrosecondsToTicks(100) &&
|
||||
!(__PIRegs[0] & 0x00010000)) {
|
||||
;
|
||||
}
|
||||
if (!(__PIRegs[0] & 0x00010000)) {
|
||||
LastState = Down = TRUE;
|
||||
__OSMaskInterrupts(OS_INTERRUPTMASK_PI_RSW);
|
||||
if (ResetCallback) {
|
||||
callback = ResetCallback;
|
||||
ResetCallback = NULL;
|
||||
callback();
|
||||
}
|
||||
}
|
||||
__PIRegs[0] = 2;
|
||||
}
|
||||
|
||||
BOOL OSGetResetButtonState(void) {
|
||||
BOOL enabled = 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 & 0x1F) {
|
||||
OSTime fire = (GameChoice & 0x1F) * 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();
|
||||
}
|
251
src/dolphin/os/OSRtc.c
Normal file
251
src/dolphin/os/OSRtc.c
Normal file
@ -0,0 +1,251 @@
|
||||
#include "global.h"
|
||||
#include "dolphin/os/OSRtc.h"
|
||||
#include "dolphin/os/OSInterrupt.h"
|
||||
|
||||
static void WriteSramCallback(s32 chan, OSContext* context);
|
||||
static BOOL WriteSram(void* buffer, u32 offset, u32 size);
|
||||
static BOOL UnlockSram(BOOL commit, u32 offset);
|
||||
|
||||
static SramControlBlock Scb ALIGN_DECL(32);
|
||||
|
||||
static void WriteSramCallback(s32 chan, OSContext* context) {
|
||||
Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset);
|
||||
if (Scb.sync) {
|
||||
Scb.offset = RTC_SRAM_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline BOOL ReadSram(void* buffer) {
|
||||
BOOL err;
|
||||
u32 cmd;
|
||||
|
||||
DCInvalidateRange(buffer, RTC_SRAM_SIZE);
|
||||
|
||||
if (!EXILock(RTC_CHAN, RTC_DEV, 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) {
|
||||
EXIUnlock(RTC_CHAN);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cmd = RTC_CMD_READ | RTC_SRAM_ADDR;
|
||||
err = FALSE;
|
||||
err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL);
|
||||
err |= !EXISync(RTC_CHAN);
|
||||
err |= !EXIDma(RTC_CHAN, buffer, RTC_SRAM_SIZE, 0, NULL);
|
||||
err |= !EXISync(RTC_CHAN);
|
||||
err |= !EXIDeselect(RTC_CHAN);
|
||||
EXIUnlock(RTC_CHAN);
|
||||
|
||||
return !err;
|
||||
}
|
||||
|
||||
BOOL WriteSram(void* buffer, u32 offset, u32 size) {
|
||||
BOOL err;
|
||||
u32 cmd;
|
||||
|
||||
if (!EXILock(RTC_CHAN, RTC_DEV, WriteSramCallback)) {
|
||||
return FALSE;
|
||||
}
|
||||
if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) {
|
||||
EXIUnlock(RTC_CHAN);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
offset <<= 6;
|
||||
cmd = RTC_CMD_WRITE | RTC_SRAM_ADDR + offset;
|
||||
err = FALSE;
|
||||
err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL);
|
||||
err |= !EXISync(RTC_CHAN);
|
||||
err |= !EXIImmEx(RTC_CHAN, buffer, (s32)size, 1);
|
||||
err |= !EXIDeselect(RTC_CHAN);
|
||||
EXIUnlock(RTC_CHAN);
|
||||
|
||||
return !err;
|
||||
}
|
||||
|
||||
void __OSInitSram(void) {
|
||||
Scb.locked = Scb.enabled = FALSE;
|
||||
Scb.sync = ReadSram(Scb.sram);
|
||||
Scb.offset = RTC_SRAM_SIZE;
|
||||
OSSetGbsMode(OSGetGbsMode());
|
||||
}
|
||||
|
||||
static void* LockSram(u32 offset) {
|
||||
BOOL enabled;
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
if (Scb.locked != FALSE) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Scb.enabled = enabled;
|
||||
Scb.locked = TRUE;
|
||||
|
||||
return Scb.sram + offset;
|
||||
}
|
||||
|
||||
OSSram* __OSLockSram() {
|
||||
return LockSram(0);
|
||||
}
|
||||
|
||||
OSSramEx* __OSLockSramEx() {
|
||||
return LockSram(sizeof(OSSram));
|
||||
}
|
||||
|
||||
static BOOL UnlockSram(BOOL commit, u32 offset) {
|
||||
u16* p;
|
||||
|
||||
if (commit) {
|
||||
if (offset == 0) {
|
||||
OSSram* sram = (OSSram*)Scb.sram;
|
||||
|
||||
if (2u < (sram->flags & 3)) {
|
||||
sram->flags &= ~3;
|
||||
}
|
||||
|
||||
sram->checkSum = sram->checkSumInv = 0;
|
||||
for (p = (u16*)&sram->counterBias; p < (u16*)(Scb.sram + sizeof(OSSram)); p++) {
|
||||
sram->checkSum += *p;
|
||||
sram->checkSumInv += ~*p;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset < Scb.offset) {
|
||||
Scb.offset = offset;
|
||||
}
|
||||
|
||||
if (Scb.offset <= 0x14) {
|
||||
OSSramEx* sram = (OSSramEx*)(Scb.sram + sizeof(OSSram));
|
||||
if (((u32)sram->gbs & 0x7c00) == 0x5000 || ((u32)sram->gbs & 0xc0) == 0xc0) {
|
||||
sram->gbs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset);
|
||||
if (Scb.sync) {
|
||||
Scb.offset = RTC_SRAM_SIZE;
|
||||
}
|
||||
}
|
||||
Scb.locked = FALSE;
|
||||
OSRestoreInterrupts(Scb.enabled);
|
||||
return Scb.sync;
|
||||
}
|
||||
|
||||
BOOL __OSUnlockSram(BOOL commit) {
|
||||
return UnlockSram(commit, 0);
|
||||
}
|
||||
|
||||
BOOL __OSUnlockSramEx(BOOL commit) {
|
||||
return UnlockSram(commit, sizeof(OSSram));
|
||||
}
|
||||
|
||||
BOOL __OSSyncSram(void) {
|
||||
return Scb.sync;
|
||||
}
|
||||
|
||||
u32 OSGetSoundMode() {
|
||||
OSSram* sram;
|
||||
u32 mode;
|
||||
|
||||
sram = __OSLockSram();
|
||||
mode = (sram->flags & 0x4) ? OS_SOUND_MODE_STEREO : OS_SOUND_MODE_MONO;
|
||||
__OSUnlockSram(FALSE);
|
||||
return mode;
|
||||
}
|
||||
|
||||
void OSSetSoundMode(u32 mode) {
|
||||
OSSram* sram;
|
||||
mode <<= 2;
|
||||
mode &= 4;
|
||||
|
||||
sram = __OSLockSram();
|
||||
if (mode == (sram->flags & 4)) {
|
||||
__OSUnlockSram(FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
sram->flags &= ~4;
|
||||
sram->flags |= mode;
|
||||
__OSUnlockSram(TRUE);
|
||||
}
|
||||
|
||||
u32 OSGetProgressiveMode() {
|
||||
OSSram* sram;
|
||||
u32 mode;
|
||||
|
||||
sram = __OSLockSram();
|
||||
mode = (sram->flags & 0x80) >> 7;
|
||||
__OSUnlockSram(FALSE);
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
void OSSetProgressiveMode(u32 mode) {
|
||||
OSSram* sram;
|
||||
mode <<= 7;
|
||||
mode &= 0x80;
|
||||
|
||||
sram = __OSLockSram();
|
||||
if (mode == (sram->flags & 0x80)) {
|
||||
__OSUnlockSram(FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
sram->flags &= ~0x80;
|
||||
sram->flags |= mode;
|
||||
__OSUnlockSram(TRUE);
|
||||
}
|
||||
|
||||
u16 OSGetWirelessID(s32 channel) {
|
||||
OSSramEx* sram;
|
||||
u16 id;
|
||||
|
||||
sram = __OSLockSramEx();
|
||||
id = sram->wirelessPadID[channel];
|
||||
__OSUnlockSramEx(FALSE);
|
||||
return id;
|
||||
}
|
||||
|
||||
void OSSetWirelessID(s32 channel, u16 id) {
|
||||
OSSramEx* sram;
|
||||
|
||||
sram = __OSLockSramEx();
|
||||
if (sram->wirelessPadID[channel] != id) {
|
||||
sram->wirelessPadID[channel] = id;
|
||||
__OSUnlockSramEx(TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
__OSUnlockSramEx(FALSE);
|
||||
}
|
||||
|
||||
u16 OSGetGbsMode() {
|
||||
OSSramEx* sram;
|
||||
u16 gbs;
|
||||
|
||||
sram = __OSLockSramEx();
|
||||
gbs = sram->gbs;
|
||||
__OSUnlockSramEx(FALSE);
|
||||
return gbs;
|
||||
}
|
||||
|
||||
void OSSetGbsMode(u16 mode) {
|
||||
OSSramEx* sram;
|
||||
|
||||
if (((u32)mode & 0x7c00) == 0x5000 || ((u32)mode & 0xc0) == 0xc0) {
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
sram = __OSLockSramEx();
|
||||
|
||||
if (mode == sram->gbs) {
|
||||
__OSUnlockSramEx(FALSE);
|
||||
return;
|
||||
}
|
||||
sram->gbs = mode;
|
||||
|
||||
__OSUnlockSramEx(TRUE);
|
||||
}
|
32
src/dolphin/os/OSSync.c
Normal file
32
src/dolphin/os/OSSync.c
Normal file
@ -0,0 +1,32 @@
|
||||
#include "dolphin/os/OSSync.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
void __OSSystemCallVectorStart();
|
||||
void __OSSystemCallVectorEnd();
|
||||
|
||||
static asm void SystemCallVector(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
entry __OSSystemCallVectorStart
|
||||
mfspr r9, HID0
|
||||
ori r10, r9, 8
|
||||
mtspr HID0, r10
|
||||
isync
|
||||
sync
|
||||
mtspr HID0, r9
|
||||
rfi
|
||||
|
||||
entry __OSSystemCallVectorEnd
|
||||
nop
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void __OSInitSystemCall(void) {
|
||||
void* addr = OSPhysicalToCached(0x00C00);
|
||||
memcpy(addr, __OSSystemCallVectorStart,
|
||||
(size_t)__OSSystemCallVectorEnd - (size_t)__OSSystemCallVectorStart);
|
||||
DCFlushRangeNoSync(addr, 0x100);
|
||||
__sync();
|
||||
ICInvalidateRange(addr, 0x100);
|
||||
}
|
901
src/dolphin/os/OSThread.c
Normal file
901
src/dolphin/os/OSThread.c
Normal file
@ -0,0 +1,901 @@
|
||||
//
|
||||
// Generated By: dol2asm
|
||||
// Translation Unit: OSThread
|
||||
//
|
||||
|
||||
#include "global.h"
|
||||
#include "dolphin/os/OSThread.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
OSThread* __OSCurrentThread : OS_BASE_CACHED + 0x00E4;
|
||||
OSThreadQueue __OSActiveThreadQueue : OS_BASE_CACHED + 0x00DC;
|
||||
volatile OSContext __OSCurrentContext : OS_BASE_CACHED + 0x00D4;
|
||||
volatile OSContext* __OSFPUContext : OS_BASE_CACHED + 0x00D8;
|
||||
|
||||
#define AddTail(queue, thread, link) \
|
||||
do { \
|
||||
OSThread* prev; \
|
||||
\
|
||||
prev = (queue)->tail; \
|
||||
if (prev == NULL) \
|
||||
(queue)->head = (thread); \
|
||||
else \
|
||||
prev->link.next = (thread); \
|
||||
(thread)->link.prev = prev; \
|
||||
(thread)->link.next = NULL; \
|
||||
(queue)->tail = (thread); \
|
||||
} while (0)
|
||||
|
||||
#define AddPrio(queue, thread, link) \
|
||||
do { \
|
||||
OSThread *prev, *next; \
|
||||
\
|
||||
for (next = (queue)->head; next && next->effective_priority <= thread->effective_priority; \
|
||||
next = next->link.next) \
|
||||
; \
|
||||
if (next == NULL) \
|
||||
AddTail(queue, thread, link); \
|
||||
else { \
|
||||
(thread)->link.next = next; \
|
||||
prev = next->link.prev; \
|
||||
next->link.prev = (thread); \
|
||||
(thread)->link.prev = prev; \
|
||||
if (prev == NULL) \
|
||||
(queue)->head = (thread); \
|
||||
else \
|
||||
prev->link.next = (thread); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RemoveItem(queue, thread, link) \
|
||||
do { \
|
||||
OSThread *next, *prev; \
|
||||
next = (thread)->link.next; \
|
||||
prev = (thread)->link.prev; \
|
||||
if (next == NULL) \
|
||||
(queue)->tail = prev; \
|
||||
else \
|
||||
next->link.prev = prev; \
|
||||
if (prev == NULL) \
|
||||
(queue)->head = next; \
|
||||
else \
|
||||
prev->link.next = next; \
|
||||
} while (0)
|
||||
|
||||
#define RemoveHead(queue, thread, link) \
|
||||
do { \
|
||||
OSThread* __next; \
|
||||
(thread) = (queue)->head; \
|
||||
__next = (thread)->link.next; \
|
||||
if (__next == NULL) \
|
||||
(queue)->tail = NULL; \
|
||||
else \
|
||||
__next->link.prev = NULL; \
|
||||
(queue)->head = __next; \
|
||||
} while (0)
|
||||
|
||||
//
|
||||
// External References:
|
||||
//
|
||||
|
||||
extern OSErrorHandlerEx __OSErrorTable[17];
|
||||
extern u32 __OSFpscrEnableBits;
|
||||
void _epilog();
|
||||
|
||||
//
|
||||
// Declarations:
|
||||
//
|
||||
|
||||
static void DefaultSwitchThreadCallback(OSThread* from, OSThread* to) {}
|
||||
|
||||
static OSSwitchThreadCallback SwitchThreadCallback = DefaultSwitchThreadCallback;
|
||||
|
||||
OSSwitchThreadCallback OSSetSwitchThreadCallback(OSSwitchThreadCallback func) {
|
||||
BOOL enable = OSDisableInterrupts();
|
||||
OSSwitchThreadCallback prev = SwitchThreadCallback;
|
||||
OSSwitchThreadCallback temp;
|
||||
if (func) {
|
||||
temp = func;
|
||||
} else {
|
||||
temp = DefaultSwitchThreadCallback;
|
||||
}
|
||||
SwitchThreadCallback = temp;
|
||||
|
||||
OSRestoreInterrupts(enable);
|
||||
if (prev == DefaultSwitchThreadCallback) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
static OSThreadQueue RunQueue[32];
|
||||
|
||||
#pragma push
|
||||
#pragma force_active on
|
||||
static OSThread IdleThread;
|
||||
#pragma pop
|
||||
|
||||
#pragma push
|
||||
#pragma force_active on
|
||||
static OSThread DefaultThread;
|
||||
#pragma pop
|
||||
|
||||
#pragma push
|
||||
#pragma force_active on
|
||||
static OSContext IdleContext;
|
||||
#pragma pop
|
||||
|
||||
static vu32 RunQueueBits;
|
||||
|
||||
static volatile BOOL RunQueueHint;
|
||||
|
||||
static volatile s32 Reschedule;
|
||||
|
||||
extern u8 _stack_end[];
|
||||
extern u8 _stack_addr[];
|
||||
|
||||
static inline void OSInitMutexQueue(OSMutexQueue* queue) {
|
||||
queue->head = queue->tail = NULL;
|
||||
}
|
||||
|
||||
static inline void OSSetCurrentThread(OSThread* thread) {
|
||||
SwitchThreadCallback(__OSCurrentThread, thread);
|
||||
__OSCurrentThread = thread;
|
||||
}
|
||||
|
||||
void __OSThreadInit() {
|
||||
OSThread* thread = &DefaultThread;
|
||||
int prio;
|
||||
|
||||
thread->state = OS_THREAD_STATE_RUNNING;
|
||||
thread->attributes = OS_THREAD_ATTR_DETACH;
|
||||
thread->effective_priority = thread->base_priority = 16;
|
||||
thread->suspend_count = 0;
|
||||
thread->exit_value = (void*)-1;
|
||||
thread->mutex = NULL;
|
||||
OSInitThreadQueue(&thread->join_queue);
|
||||
OSInitMutexQueue(&thread->owned_mutexes);
|
||||
|
||||
__OSFPUContext = &thread->context;
|
||||
|
||||
OSClearContext(&thread->context);
|
||||
OSSetCurrentContext(&thread->context);
|
||||
thread->stack_base = (void*)_stack_addr;
|
||||
thread->stack_end = (void*)_stack_end;
|
||||
*(thread->stack_end) = OS_THREAD_STACK_MAGIC;
|
||||
|
||||
OSSetCurrentThread(thread);
|
||||
OSClearStack(0);
|
||||
|
||||
RunQueueBits = 0;
|
||||
RunQueueHint = FALSE;
|
||||
for (prio = OS_PRIORITY_MIN; prio <= OS_PRIORITY_MAX; ++prio) {
|
||||
OSInitThreadQueue(&RunQueue[prio]);
|
||||
}
|
||||
|
||||
OSInitThreadQueue(&__OSActiveThreadQueue);
|
||||
AddTail(&__OSActiveThreadQueue, thread, active_threads_link);
|
||||
OSClearContext(&IdleContext);
|
||||
Reschedule = 0;
|
||||
}
|
||||
|
||||
void OSInitThreadQueue(OSThreadQueue* queue) {
|
||||
queue->tail = NULL;
|
||||
queue->head = NULL;
|
||||
}
|
||||
|
||||
OSThread* OSGetCurrentThread(void) {
|
||||
return OS_CURRENT_THREAD;
|
||||
}
|
||||
|
||||
BOOL OSIsThreadTerminated(OSThread* thread) {
|
||||
return thread->state == OS_THREAD_STATE_DEAD || thread->state == OS_THREAD_STATE_UNINITIALIZED ?
|
||||
TRUE :
|
||||
FALSE;
|
||||
}
|
||||
|
||||
s32 OSDisableScheduler(void) {
|
||||
BOOL intr = OSDisableInterrupts();
|
||||
s32 ret = Reschedule++;
|
||||
OSRestoreInterrupts(intr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 OSEnableScheduler(void) {
|
||||
BOOL intr = OSDisableInterrupts();
|
||||
s32 ret = Reschedule--;
|
||||
OSRestoreInterrupts(intr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void SetRun(OSThread* thread) {
|
||||
thread->queue = &RunQueue[thread->effective_priority];
|
||||
AddTail(thread->queue, thread, link);
|
||||
RunQueueBits |= 1u << (OS_PRIORITY_MAX - thread->effective_priority);
|
||||
RunQueueHint = TRUE;
|
||||
}
|
||||
|
||||
#pragma dont_inline on
|
||||
static void UnsetRun(OSThread* thread) {
|
||||
OSThreadQueue* queue;
|
||||
OSThread* next;
|
||||
OSThread* prev;
|
||||
|
||||
prev = thread->link.next;
|
||||
queue = thread->queue;
|
||||
next = thread->link.prev;
|
||||
|
||||
if (prev == NULL) {
|
||||
queue->tail = next;
|
||||
} else {
|
||||
prev->link.prev = next;
|
||||
}
|
||||
|
||||
if (next == NULL) {
|
||||
queue->head = prev;
|
||||
} else {
|
||||
next->link.next = prev;
|
||||
}
|
||||
|
||||
if (queue->head == NULL) {
|
||||
RunQueueBits &= ~(1 << 31 - thread->effective_priority);
|
||||
}
|
||||
|
||||
thread->queue = NULL;
|
||||
}
|
||||
#pragma dont_inline reset
|
||||
|
||||
s32 __OSGetEffectivePriority(OSThread* thread) {
|
||||
s32 prio = thread->base_priority;
|
||||
|
||||
OSMutex* mutex;
|
||||
for (mutex = thread->owned_mutexes.head; mutex != NULL; mutex = mutex->link.next) {
|
||||
OSThread* mutexThread = mutex->queue.head;
|
||||
if (mutexThread != NULL && mutexThread->effective_priority < prio) {
|
||||
prio = mutexThread->effective_priority;
|
||||
}
|
||||
}
|
||||
|
||||
return prio;
|
||||
}
|
||||
|
||||
static OSThread* SetEffectivePriority(OSThread* thread, s32 priority) {
|
||||
switch (thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
UnsetRun(thread);
|
||||
thread->effective_priority = priority;
|
||||
SetRun(thread);
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
RemoveItem(thread->queue, thread, link);
|
||||
thread->effective_priority = priority;
|
||||
AddPrio(thread->queue, thread, link);
|
||||
if (thread->mutex) {
|
||||
return thread->mutex->thread;
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
RunQueueHint = TRUE;
|
||||
thread->effective_priority = priority;
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void UpdatePriority(OSThread* thread) {
|
||||
OSPriority priority;
|
||||
|
||||
do {
|
||||
if (0 < thread->suspend_count) {
|
||||
break;
|
||||
}
|
||||
priority = __OSGetEffectivePriority(thread);
|
||||
if (thread->effective_priority == priority) {
|
||||
break;
|
||||
}
|
||||
thread = SetEffectivePriority(thread, priority);
|
||||
} while (thread);
|
||||
}
|
||||
|
||||
void __OSPromoteThread(OSThread* thread, s32 priority) {
|
||||
do {
|
||||
if (thread->suspend_count > 0 || thread->effective_priority <= priority) {
|
||||
break;
|
||||
}
|
||||
|
||||
thread = SetEffectivePriority(thread, priority);
|
||||
} while (thread != NULL);
|
||||
}
|
||||
|
||||
static inline void __OSSwitchThread(OSThread* nextThread) {
|
||||
OSSetCurrentThread(nextThread);
|
||||
OSSetCurrentContext(&nextThread->context);
|
||||
OSLoadContext(&nextThread->context);
|
||||
}
|
||||
|
||||
inline OSThread* i_OSGetCurrentThread(void) {
|
||||
return OS_CURRENT_THREAD;
|
||||
}
|
||||
|
||||
static OSThread* SelectThread(BOOL yield) {
|
||||
OSContext* currentContext;
|
||||
OSThread* currentThread;
|
||||
OSThread* nextThread;
|
||||
OSPriority priority;
|
||||
OSThreadQueue* queue;
|
||||
|
||||
if (0 < Reschedule) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
currentContext = OSGetCurrentContext();
|
||||
currentThread = i_OSGetCurrentThread();
|
||||
if (currentContext != ¤tThread->context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (currentThread) {
|
||||
if (currentThread->state == OS_THREAD_STATE_RUNNING) {
|
||||
if (!yield) {
|
||||
priority = __cntlzw(RunQueueBits);
|
||||
if (currentThread->effective_priority <= priority) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
currentThread->state = OS_THREAD_STATE_READY;
|
||||
SetRun(currentThread);
|
||||
}
|
||||
|
||||
if (!(currentThread->context.state & OS_CONTEXT_STATE_EXC) &&
|
||||
OSSaveContext(¤tThread->context))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (RunQueueBits == 0) {
|
||||
OSSetCurrentThread(NULL);
|
||||
OSSetCurrentContext(&IdleContext);
|
||||
do {
|
||||
OSEnableInterrupts();
|
||||
while (RunQueueBits == 0)
|
||||
;
|
||||
OSDisableInterrupts();
|
||||
} while (RunQueueBits == 0);
|
||||
|
||||
OSClearContext(&IdleContext);
|
||||
}
|
||||
|
||||
RunQueueHint = FALSE;
|
||||
|
||||
priority = __cntlzw(RunQueueBits);
|
||||
queue = &RunQueue[priority];
|
||||
RemoveHead(queue, nextThread, link);
|
||||
if (queue->head == 0) {
|
||||
RunQueueBits &= ~(1u << (OS_PRIORITY_MAX - priority));
|
||||
}
|
||||
nextThread->queue = NULL;
|
||||
nextThread->state = OS_THREAD_STATE_RUNNING;
|
||||
__OSSwitchThread(nextThread);
|
||||
return nextThread;
|
||||
}
|
||||
|
||||
void __OSReschedule(void) {
|
||||
if (!RunQueueHint) {
|
||||
return;
|
||||
}
|
||||
|
||||
SelectThread(FALSE);
|
||||
}
|
||||
|
||||
void OSYieldThread(void) {
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
SelectThread(TRUE);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
BOOL OSCreateThread(OSThread* thread_, void* func, void* param, void* stackBase, u32 stackSize,
|
||||
s32 priority, u16 attribute) {
|
||||
BOOL enabled;
|
||||
u32 i;
|
||||
u32* stack;
|
||||
OSThread* thread;
|
||||
u32 stack1, stack2;
|
||||
|
||||
if (priority < 0 || priority > 31) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
thread = thread_;
|
||||
|
||||
thread->state = OS_THREAD_STATE_READY;
|
||||
thread->attributes = attribute & 1;
|
||||
thread->base_priority = priority;
|
||||
thread->effective_priority = priority;
|
||||
thread->suspend_count = 1;
|
||||
thread->exit_value = (void*)-1;
|
||||
thread->mutex = NULL;
|
||||
thread->join_queue.tail = NULL;
|
||||
thread->join_queue.head = NULL;
|
||||
thread->owned_mutexes.tail = NULL;
|
||||
thread->owned_mutexes.head = NULL;
|
||||
stack = (u32*)((u32)stackBase & 0xfffffff8);
|
||||
stack[-2] = 0;
|
||||
stack[-1] = 0;
|
||||
OSInitContext(&thread->context, (u32)func, (u32)stack - 8);
|
||||
thread->context.lr = (u32)OSExitThread;
|
||||
thread->context.gpr[3] = (u32)param;
|
||||
thread->stack_base = (u8*)stackBase;
|
||||
thread->stack_end = (void*)((u32)stackBase - stackSize);
|
||||
*(u32*)thread->stack_end = OS_THREAD_STACK_MAGIC;
|
||||
thread->error_code = NULL;
|
||||
thread->data[0] = NULL;
|
||||
thread->data[1] = NULL;
|
||||
enabled = OSDisableInterrupts();
|
||||
if (__OSErrorTable[16]) {
|
||||
thread->context.srr1 |= 0x900;
|
||||
thread->context.state |= 1;
|
||||
thread->context.fpscr = (__OSFpscrEnableBits & 0xf8) | 4;
|
||||
for (i = 0; i < 32; ++i) {
|
||||
*(u64*)&thread->context.fpr[i] = (u64)0xffffffffffffffffLL;
|
||||
*(u64*)&thread->context.ps[i] = (u64)0xffffffffffffffffLL;
|
||||
}
|
||||
}
|
||||
|
||||
AddTail(&OS_THREAD_QUEUE, thread, active_threads_link);
|
||||
OSRestoreInterrupts(enabled);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void OSExitThread(void* exitValue) {
|
||||
OSThread* currentThread;
|
||||
BOOL enabled;
|
||||
enabled = OSDisableInterrupts();
|
||||
currentThread = OS_CURRENT_THREAD;
|
||||
OSClearContext(¤tThread->context);
|
||||
|
||||
if (currentThread->attributes & OS_THREAD_ATTR_DETACH) {
|
||||
RemoveItem(&OS_THREAD_QUEUE, currentThread, active_threads_link);
|
||||
currentThread->state = OS_THREAD_STATE_UNINITIALIZED;
|
||||
} else {
|
||||
currentThread->state = OS_THREAD_STATE_DEAD;
|
||||
currentThread->exit_value = exitValue;
|
||||
}
|
||||
|
||||
__OSUnlockAllMutex(currentThread);
|
||||
OSWakeupThread(¤tThread->join_queue);
|
||||
RunQueueHint = TRUE;
|
||||
|
||||
if (RunQueueHint) {
|
||||
SelectThread(FALSE);
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSCancelThread(OSThread* thread) {
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
switch (thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
if (!(0 < thread->suspend_count)) {
|
||||
UnsetRun(thread);
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
RunQueueHint = TRUE;
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
RemoveItem(thread->queue, thread, link);
|
||||
thread->queue = NULL;
|
||||
if (!(0 < thread->suspend_count) && thread->mutex) {
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OSRestoreInterrupts(enabled);
|
||||
return;
|
||||
}
|
||||
|
||||
OSClearContext(&thread->context);
|
||||
if (thread->attributes & OS_THREAD_ATTR_DETACH) {
|
||||
RemoveItem(&__OSActiveThreadQueue, thread, active_threads_link);
|
||||
thread->state = 0;
|
||||
} else {
|
||||
thread->state = OS_THREAD_STATE_DEAD;
|
||||
}
|
||||
|
||||
__OSUnlockAllMutex(thread);
|
||||
|
||||
OSWakeupThread(&thread->join_queue);
|
||||
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSDetachThread(OSThread* thread) {
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
thread->attributes |= OS_THREAD_ATTR_DETACH;
|
||||
|
||||
if (thread->state == OS_THREAD_STATE_DEAD) {
|
||||
RemoveItem(&__OSActiveThreadQueue, thread, active_threads_link);
|
||||
thread->state = OS_THREAD_STATE_UNINITIALIZED;
|
||||
}
|
||||
|
||||
OSWakeupThread(&thread->join_queue);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
s32 OSResumeThread(OSThread* thread) {
|
||||
BOOL enabled;
|
||||
s32 suspendCount;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
suspendCount = thread->suspend_count--;
|
||||
if (thread->suspend_count < 0) {
|
||||
thread->suspend_count = 0;
|
||||
} else if (thread->suspend_count == 0) {
|
||||
switch (thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
thread->effective_priority = __OSGetEffectivePriority(thread);
|
||||
SetRun(thread);
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
RemoveItem(thread->queue, thread, link);
|
||||
thread->effective_priority = __OSGetEffectivePriority(thread);
|
||||
AddPrio(thread->queue, thread, link);
|
||||
if (thread->mutex) {
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
break;
|
||||
}
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return suspendCount;
|
||||
}
|
||||
|
||||
s32 OSSuspendThread(OSThread* thread) {
|
||||
BOOL enabled;
|
||||
s32 suspendCount;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
suspendCount = thread->suspend_count++;
|
||||
if (suspendCount == 0) {
|
||||
switch (thread->state) {
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
RunQueueHint = TRUE;
|
||||
thread->state = OS_THREAD_STATE_READY;
|
||||
break;
|
||||
case OS_THREAD_STATE_READY:
|
||||
UnsetRun(thread);
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
RemoveItem(thread->queue, thread, link);
|
||||
thread->effective_priority = 32;
|
||||
AddTail(thread->queue, thread, link);
|
||||
if (thread->mutex) {
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return suspendCount;
|
||||
}
|
||||
|
||||
void OSSleepThread(OSThreadQueue* queue) {
|
||||
BOOL enabled;
|
||||
OSThread* currentThread;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
currentThread = OSGetCurrentThread();
|
||||
|
||||
currentThread->state = OS_THREAD_STATE_WAITING;
|
||||
currentThread->queue = queue;
|
||||
AddPrio(queue, currentThread, link);
|
||||
RunQueueHint = TRUE;
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSWakeupThread(OSThreadQueue* queue) {
|
||||
BOOL enabled;
|
||||
OSThread* thread;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
while (queue->head) {
|
||||
RemoveHead(queue, thread, link);
|
||||
thread->state = OS_THREAD_STATE_READY;
|
||||
if (!(0 < thread->suspend_count)) {
|
||||
SetRun(thread);
|
||||
}
|
||||
}
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
s32 OSSetThreadPriority(OSThread* thread, s32 priority) {
|
||||
BOOL enabled;
|
||||
|
||||
if (priority < 0 || priority > 31) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
if ((s32)thread->base_priority != priority) {
|
||||
thread->base_priority = priority;
|
||||
|
||||
UpdatePriority(thread);
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
s32 OSGetThreadPriority(OSThread* thread) {
|
||||
return thread->base_priority;
|
||||
}
|
||||
|
||||
s32 CheckThreadQueue(OSThreadQueue* thread) {
|
||||
OSThread* current;
|
||||
if (thread->head && thread->head->link.prev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (thread->tail && thread->tail->link.next) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
current = thread->head;
|
||||
|
||||
while (current) {
|
||||
if (current->link.next && current != current->link.next->link.prev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (current->link.prev && current != current->link.prev->link.next) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
current = current->link.next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL isMember(OSThreadQueue* queue, OSThread* thread) {
|
||||
OSThread* current = queue->head;
|
||||
while (current != NULL) {
|
||||
if (thread == current) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
current = current->link.next;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
s32 OSCheckActiveThreads(void) {
|
||||
s32 i;
|
||||
OSThread* thread;
|
||||
s32 rv = 0;
|
||||
BOOL enabled;
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
for (i = 0; i <= 31; i++) {
|
||||
if (RunQueueBits & (1 << (31 - i))) {
|
||||
if (RunQueue[i].head == NULL || RunQueue[i].tail == NULL) {
|
||||
OSReport("OSCheckActiveThreads: Failed RunQueue[prio].head != NULL && "
|
||||
"RunQueue[prio].tail != NULL in %d\n",
|
||||
0x5e0);
|
||||
OSPanic(__FILE__, 0x5e0, "");
|
||||
}
|
||||
} else {
|
||||
if (RunQueue[i].head != NULL || RunQueue[i].tail != NULL) {
|
||||
OSReport("OSCheckActiveThreads: Failed RunQueue[prio].head == NULL && "
|
||||
"RunQueue[prio].tail == NULL in %d\n",
|
||||
0x5e5);
|
||||
OSPanic(__FILE__, 0x5e5, "");
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckThreadQueue(&RunQueue[i]) == 0) {
|
||||
OSReport("OSCheckActiveThreads: Failed CheckThreadQueue(&RunQueue[prio]) in %d\n",
|
||||
0x5e7);
|
||||
OSPanic(__FILE__, 0x5e7, "");
|
||||
}
|
||||
}
|
||||
|
||||
if (OS_THREAD_QUEUE.head != NULL && OS_THREAD_QUEUE.head->active_threads_link.prev != NULL) {
|
||||
OSReport("OSCheckActiveThreads: Failed __OSActiveThreadQueue.head == NULL || "
|
||||
"__OSActiveThreadQueue.head->linkActive.prev == NULL in %d\n",
|
||||
0x5ec);
|
||||
OSPanic(__FILE__, 0x5ec, "");
|
||||
}
|
||||
|
||||
if (OS_THREAD_QUEUE.tail != NULL && OS_THREAD_QUEUE.tail->active_threads_link.next != NULL) {
|
||||
OSReport("OSCheckActiveThreads: Failed __OSActiveThreadQueue.tail == NULL || "
|
||||
"__OSActiveThreadQueue.tail->linkActive.next == NULL in %d\n",
|
||||
0x5ee);
|
||||
OSPanic(__FILE__, 0x5ee, "");
|
||||
}
|
||||
|
||||
thread = OS_THREAD_QUEUE.head;
|
||||
|
||||
while (thread != NULL) {
|
||||
rv++;
|
||||
if (thread->active_threads_link.next != NULL &&
|
||||
thread != thread->active_threads_link.next->active_threads_link.prev)
|
||||
{
|
||||
OSReport("OSCheckActiveThreads: Failed thread->linkActive.next == NULL || thread == "
|
||||
"thread->linkActive.next->linkActive.prev in %d\n",
|
||||
0x5f6);
|
||||
OSPanic(__FILE__, 0x5f6, "");
|
||||
}
|
||||
|
||||
if (thread->active_threads_link.prev != NULL &&
|
||||
thread != thread->active_threads_link.prev->active_threads_link.next)
|
||||
{
|
||||
OSReport("OSCheckActiveThreads: Failed thread->linkActive.prev == NULL || thread == "
|
||||
"thread->linkActive.prev->linkActive.next in %d\n",
|
||||
0x5f8);
|
||||
OSPanic(__FILE__, 0x5f8, "");
|
||||
}
|
||||
|
||||
if (*(u32*)thread->stack_end != OS_THREAD_STACK_MAGIC) {
|
||||
OSReport(
|
||||
"OSCheckActiveThreads: Failed *(thread->stackEnd) == OS_THREAD_STACK_MAGIC in %d\n",
|
||||
0x5fb);
|
||||
OSPanic(__FILE__, 0x5fb, "");
|
||||
}
|
||||
|
||||
if (OS_PRIORITY_MIN > thread->effective_priority ||
|
||||
thread->effective_priority > OS_PRIORITY_MAX + 1)
|
||||
{
|
||||
OSReport("OSCheckActiveThreads: Failed OS_PRIORITY_MIN <= thread->priority && "
|
||||
"thread->priority <= OS_PRIORITY_MAX+1 in %d\n",
|
||||
0x5fe);
|
||||
OSPanic(__FILE__, 0x5fe, "");
|
||||
}
|
||||
|
||||
if (thread->suspend_count < 0) {
|
||||
OSReport("OSCheckActiveThreads: Failed 0 <= thread->suspend in %d\n", 0x5ff);
|
||||
OSPanic(__FILE__, 0x5ff, "");
|
||||
}
|
||||
|
||||
if (!CheckThreadQueue(&thread->join_queue)) {
|
||||
OSReport("OSCheckActiveThreads: Failed CheckThreadQueue(&thread->queueJoin) in %d\n",
|
||||
0x600);
|
||||
OSPanic(__FILE__, 0x600, "");
|
||||
}
|
||||
|
||||
switch (thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
if (thread->suspend_count <= 0) {
|
||||
if (thread->queue != &RunQueue[thread->effective_priority]) {
|
||||
OSReport("OSCheckActiveThreads: Failed thread->queue == "
|
||||
"&RunQueue[thread->priority] in %d\n",
|
||||
0x606);
|
||||
OSPanic(__FILE__, 0x606, "");
|
||||
}
|
||||
|
||||
if (!isMember(&RunQueue[thread->effective_priority], thread)) {
|
||||
OSReport("OSCheckActiveThreads: Failed IsMember(&RunQueue[thread->priority], "
|
||||
"thread) in %d\n",
|
||||
0x607);
|
||||
OSPanic(__FILE__, 0x607, "");
|
||||
}
|
||||
|
||||
if (thread->effective_priority != __OSGetEffectivePriority(thread)) {
|
||||
OSReport("OSCheckActiveThreads: Failed thread->priority == "
|
||||
"__OSGetEffectivePriority(thread) in %d\n",
|
||||
0x608);
|
||||
OSPanic(__FILE__, 0x608, "");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
if (thread->suspend_count > 0) {
|
||||
OSReport("OSCheckActiveThreads: Failed !IsSuspended(thread->suspend) in %d\n",
|
||||
0x60c);
|
||||
OSPanic(__FILE__, 0x60c, "");
|
||||
}
|
||||
|
||||
if (thread->queue != NULL) {
|
||||
OSReport("OSCheckActiveThreads: Failed thread->queue == NULL in %d\n", 0x60d);
|
||||
OSPanic(__FILE__, 0x60d, "");
|
||||
}
|
||||
|
||||
if (thread->effective_priority != __OSGetEffectivePriority(thread)) {
|
||||
OSReport("OSCheckActiveThreads: Failed thread->priority == "
|
||||
"__OSGetEffectivePriority(thread) in %d\n",
|
||||
0x60e);
|
||||
OSPanic(__FILE__, 0x60e, "");
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
if (thread->queue == NULL) {
|
||||
OSReport("OSCheckActiveThreads: Failed thread->queue != NULL in %d\n", 0x611);
|
||||
OSPanic(__FILE__, 0x611, "");
|
||||
}
|
||||
|
||||
if (CheckThreadQueue(thread->queue) == 0) {
|
||||
OSReport("OSCheckActiveThreads: Failed CheckThreadQueue(thread->queue) in %d\n",
|
||||
0x612);
|
||||
OSPanic(__FILE__, 0x612, "");
|
||||
}
|
||||
|
||||
if (!isMember(thread->queue, thread)) {
|
||||
OSReport("OSCheckActiveThreads: Failed IsMember(thread->queue, thread) in %d\n",
|
||||
0x613);
|
||||
OSPanic(__FILE__, 0x613, "");
|
||||
}
|
||||
|
||||
if (thread->suspend_count <= 0) {
|
||||
if (thread->effective_priority != __OSGetEffectivePriority(thread)) {
|
||||
OSReport("OSCheckActiveThreads: Failed thread->priority == "
|
||||
"__OSGetEffectivePriority(thread) in %d\n",
|
||||
0x616);
|
||||
OSPanic(__FILE__, 0x616, "");
|
||||
}
|
||||
} else if (thread->effective_priority != 32) {
|
||||
OSReport("OSCheckActiveThreads: Failed thread->priority == 32 in %d\n", 0x61a);
|
||||
OSPanic(__FILE__, 0x61a, "");
|
||||
}
|
||||
|
||||
if (__OSCheckDeadLock(thread)) {
|
||||
OSReport("OSCheckActiveThreads: Failed !__OSCheckDeadLock(thread) in %d\n", 0x61c);
|
||||
OSPanic(__FILE__, 0x61c, "");
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_DEAD:
|
||||
if (thread->owned_mutexes.head != NULL || thread->owned_mutexes.tail != NULL) {
|
||||
OSReport("OSCheckActiveThreads: Failed thread->queueMutex.head == NULL && "
|
||||
"thread->queueMutex.tail == NULL in %d\n",
|
||||
0x620);
|
||||
OSPanic(__FILE__, 0x620, "");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OSReport("OSCheckActiveThreads: Failed. unkown thread state (%d) of thread %p\n",
|
||||
thread->state, thread);
|
||||
OSPanic(__FILE__, 0x626, "");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!__OSCheckMutexes(thread)) {
|
||||
OSReport("OSCheckActiveThreads: Failed __OSCheckMutexes(thread) in %d\n", 0x62b);
|
||||
OSPanic(__FILE__, 0x62b, "");
|
||||
}
|
||||
|
||||
thread = thread->active_threads_link.next;
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void OSClearStack(u8 val) {
|
||||
u32* sp;
|
||||
u32* p;
|
||||
u32 pattern;
|
||||
|
||||
pattern = ((u32)val << 24) | ((u32)val << 16) | ((u32)val << 8) | (u32)val;
|
||||
sp = (u32*)OSGetStackPointer();
|
||||
for (p = ((u32*)__OSCurrentThread->stack_end) + 1; p < sp; ++p) {
|
||||
*p = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
extern u8 data_804516D0[8];
|
||||
u8 data_804516D0[8] ALIGN_DECL(8);
|
138
src/dolphin/os/OSTime.c
Normal file
138
src/dolphin/os/OSTime.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include "dolphin/os/OSTime.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
#define OS_TIME_MONTH_MAX 12
|
||||
#define OS_TIME_WEEK_DAY_MAX 7
|
||||
#define OS_TIME_YEAR_DAY_MAX 365
|
||||
|
||||
asm OSTime OSGetTime(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mftbu r3
|
||||
mftb r4, 0x10C
|
||||
|
||||
mftbu r5
|
||||
cmpw r3, r5
|
||||
bne OSGetTime
|
||||
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
asm OSTick OSGetTick(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
mftb r3, 0x10C
|
||||
blr
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
#define OS_SYSTEMTIME_BASE 0x30D8
|
||||
|
||||
OSTime __OSGetSystemTime(void) {
|
||||
BOOL enabled;
|
||||
OSTime* timeAdjustAddr = (OSTime*)(OS_BASE_CACHED + OS_SYSTEMTIME_BASE);
|
||||
OSTime result;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
result = *timeAdjustAddr + OSGetTime();
|
||||
OSRestoreInterrupts(enabled);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
OSTime __OSTimeToSystemTime(OSTime time) {
|
||||
BOOL enabled;
|
||||
OSTime* timeAdjustAddr = (OSTime*)(OS_BASE_CACHED + OS_SYSTEMTIME_BASE);
|
||||
OSTime result;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
result = *timeAdjustAddr + time;
|
||||
OSRestoreInterrupts(enabled);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// End of each month in standard year
|
||||
static s32 YearDays[] = {
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
|
||||
};
|
||||
|
||||
// End of each month in leap year
|
||||
static s32 LeapYearDays[] = {
|
||||
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335,
|
||||
};
|
||||
|
||||
static inline BOOL IsLeapYear(s32 year) {
|
||||
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
static inline s32 GetYearDays(s32 year, s32 mon) {
|
||||
return (IsLeapYear(year) ? LeapYearDays : YearDays)[mon];
|
||||
}
|
||||
|
||||
static inline s32 GetLeapDays(s32 year) {
|
||||
if (year < 1) {
|
||||
return 0;
|
||||
}
|
||||
return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400;
|
||||
}
|
||||
|
||||
static void GetDates(s32 days, OSCalendarTime* cal) {
|
||||
s32 year;
|
||||
s32 totalDays;
|
||||
s32* p_days;
|
||||
s32 month;
|
||||
cal->week_day = (days + 6) % OS_TIME_WEEK_DAY_MAX;
|
||||
|
||||
for (year = days / OS_TIME_YEAR_DAY_MAX;
|
||||
days < (totalDays = year * OS_TIME_YEAR_DAY_MAX + GetLeapDays(year));)
|
||||
{
|
||||
year--;
|
||||
}
|
||||
|
||||
days -= totalDays;
|
||||
cal->year = year;
|
||||
cal->year_day = days;
|
||||
|
||||
p_days = IsLeapYear(year) ? LeapYearDays : YearDays;
|
||||
month = OS_TIME_MONTH_MAX;
|
||||
while (days < p_days[--month]) {
|
||||
;
|
||||
}
|
||||
cal->month = month;
|
||||
cal->day_of_month = days - p_days[month] + 1;
|
||||
}
|
||||
|
||||
#define BIAS (2000 * 365 + (2000 + 3) / 4 - (2000 - 1) / 100 + (2000 - 1) / 400)
|
||||
|
||||
#pragma dont_inline on
|
||||
void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td) {
|
||||
int days;
|
||||
int secs;
|
||||
OSTime d;
|
||||
|
||||
d = ticks % OSSecondsToTicks(1);
|
||||
if (d < 0) {
|
||||
d += OSSecondsToTicks(1);
|
||||
}
|
||||
td->microseconds = (int)(OSTicksToMicroseconds(d) % 1000);
|
||||
td->milliseconds = (int)(OSTicksToMilliseconds(d) % 1000);
|
||||
|
||||
ticks -= d;
|
||||
days = (int)(OSTicksToSeconds(ticks) / 86400 + BIAS);
|
||||
secs = (int)(OSTicksToSeconds(ticks) % 86400);
|
||||
if (secs < 0) {
|
||||
days -= 1;
|
||||
secs += 24 * 60 * 60;
|
||||
}
|
||||
|
||||
GetDates(days, td);
|
||||
|
||||
td->hours = secs / 60 / 60;
|
||||
td->minutes = (secs / 60) % 60;
|
||||
td->seconds = secs % 60;
|
||||
}
|
||||
#pragma dont_inline reset
|
49
src/dolphin/os/__ppc_eabi_init.cpp
Normal file
49
src/dolphin/os/__ppc_eabi_init.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
//
|
||||
// __ppc_eabi_init
|
||||
//
|
||||
|
||||
#include "global.h"
|
||||
#include "dolphin/base/PPCArch.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//
|
||||
// Forward References:
|
||||
//
|
||||
|
||||
void __init_user();
|
||||
void __init_cpp();
|
||||
void _ExitProcess();
|
||||
|
||||
//
|
||||
// External References:
|
||||
//
|
||||
|
||||
typedef void (*voidfunctionptr)(); // pointer to function returning void
|
||||
extern voidfunctionptr __init_cpp_exceptions_reference[];
|
||||
|
||||
void __init_user(void) {
|
||||
__init_cpp();
|
||||
}
|
||||
|
||||
#pragma peephole off
|
||||
void __init_cpp(void) {
|
||||
/**
|
||||
* call static initializers
|
||||
*/
|
||||
voidfunctionptr* constructor;
|
||||
for (constructor = __init_cpp_exceptions_reference; *constructor; constructor++) {
|
||||
(*constructor)();
|
||||
}
|
||||
}
|
||||
#pragma peephole reset
|
||||
|
||||
void _ExitProcess(void) {
|
||||
PPCHalt();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
160
src/dolphin/os/__start.c
Normal file
160
src/dolphin/os/__start.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include "stdlib.h"
|
||||
#include "global.h"
|
||||
// #include "init.h"
|
||||
|
||||
//
|
||||
// Forward References:
|
||||
//
|
||||
|
||||
SECTION_INIT void __check_pad3(void);
|
||||
SECTION_INIT void __set_debug_bba(void);
|
||||
SECTION_INIT u8 __get_debug_bba(void);
|
||||
SECTION_INIT void __start(void);
|
||||
|
||||
//
|
||||
// External References:
|
||||
//
|
||||
|
||||
void main();
|
||||
void OSInit();
|
||||
void OSResetSystem(s32, s32, s32);
|
||||
void __init_user();
|
||||
void DBInit();
|
||||
void InitMetroTRK();
|
||||
void InitMetroTRK_BBA();
|
||||
extern u8 data_804516D0;
|
||||
void __init_data();
|
||||
void __init_hardware();
|
||||
void __init_registers();
|
||||
|
||||
//
|
||||
// Declarations:
|
||||
//
|
||||
|
||||
SECTION_INIT void __check_pad3(void) {
|
||||
if ((*(u16*)0x800030E4 & 0xEEF) == 0xEEF) {
|
||||
OSResetSystem(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void __set_debug_bba(void) {
|
||||
data_804516D0 = 1;
|
||||
}
|
||||
|
||||
SECTION_INIT u8 __get_debug_bba(void) {
|
||||
return data_804516D0;
|
||||
}
|
||||
|
||||
SECTION_INIT asm void __start(void) {
|
||||
// clang-format off
|
||||
nofralloc
|
||||
|
||||
bl __init_registers
|
||||
bl __init_hardware
|
||||
li r0, -1
|
||||
stwu r1, -8(r1)
|
||||
stw r0, 4(r1)
|
||||
stw r0, 0(r1)
|
||||
bl __init_data
|
||||
li r0, 0
|
||||
lis r6, 0x8000
|
||||
addi r6, r6, 0x0044
|
||||
stw r0, 0(r6)
|
||||
lis r6, 0x8000
|
||||
addi r6, r6, 0x00F4
|
||||
lwz r6, 0(r6)
|
||||
cmplwi r6, 0
|
||||
beq lbl_8000319C
|
||||
lwz r7, 0xc(r6)
|
||||
b lbl_800031BC
|
||||
|
||||
lbl_8000319C:
|
||||
lis r5, 0x8000
|
||||
addi r5, r5, 0x0034
|
||||
lwz r5, 0(r5)
|
||||
cmplwi r5, 0
|
||||
beq lbl_800031F8
|
||||
lis r7, 0x8000
|
||||
addi r7, r7, 0x30E8
|
||||
lwz r7, 0(r7)
|
||||
|
||||
lbl_800031BC:
|
||||
li r5, 0
|
||||
cmplwi r7, 2
|
||||
beq lbl_800031E8
|
||||
cmplwi r7, 3
|
||||
li r5, 1
|
||||
beq lbl_800031E8
|
||||
cmplwi r7, 4
|
||||
bne lbl_800031F8
|
||||
li r5, 2
|
||||
bl __set_debug_bba
|
||||
b lbl_800031F8
|
||||
|
||||
lbl_800031E8:
|
||||
lis r6, InitMetroTRK@ha
|
||||
addi r6, r6, InitMetroTRK@l
|
||||
mtlr r6
|
||||
blrl
|
||||
|
||||
lbl_800031F8:
|
||||
lis r6, 0x8000
|
||||
addi r6, r6, 0x00F4
|
||||
lwz r5, 0(r6)
|
||||
cmplwi r5, 0
|
||||
beq+ lbl_80003258
|
||||
lwz r6, 8(r5)
|
||||
cmplwi r6, 0
|
||||
beq+ lbl_80003258
|
||||
add r6, r5, r6
|
||||
lwz r14, 0(r6)
|
||||
cmplwi r14, 0
|
||||
beq lbl_80003258
|
||||
addi r15, r6, 4
|
||||
mtctr r14
|
||||
|
||||
lbl_80003230:
|
||||
addi r6, r6, 4
|
||||
lwz r7, 0(r6)
|
||||
add r7, r7, r5
|
||||
stw r7, 0(r6)
|
||||
bdnz lbl_80003230
|
||||
lis r5, 0x8000
|
||||
addi r5, r5, 0x0034
|
||||
rlwinm r7, r15, 0, 0, 0x1a
|
||||
stw r7, 0(r5)
|
||||
b lbl_80003260
|
||||
|
||||
lbl_80003258:
|
||||
li r14, 0
|
||||
li r15, 0
|
||||
|
||||
lbl_80003260:
|
||||
bl DBInit
|
||||
bl OSInit
|
||||
lis r4, 0x8000
|
||||
addi r4, r4, 0x30E6
|
||||
lhz r3, 0(r4)
|
||||
andi. r5, r3, 0x8000
|
||||
beq lbl_80003288
|
||||
andi. r3, r3, 0x7fff
|
||||
cmplwi r3, 1
|
||||
bne lbl_8000328C
|
||||
|
||||
lbl_80003288:
|
||||
bl __check_pad3
|
||||
|
||||
lbl_8000328C:
|
||||
bl __get_debug_bba
|
||||
cmplwi r3, 1
|
||||
bne lbl_8000329C
|
||||
bl InitMetroTRK_BBA
|
||||
|
||||
lbl_8000329C:
|
||||
bl __init_user
|
||||
mr r3, r14
|
||||
mr r4, r15
|
||||
bl main
|
||||
b exit
|
||||
// clang-format on
|
||||
}
|
@ -45,22 +45,22 @@ extern "C" int search_partial_address(void* address, int* module_id, int* sectio
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
OSModuleInfo* module = *(OSModuleInfo**)0x800030C8;
|
||||
for (; module != NULL; module = (OSModuleInfo*)module->mNext) {
|
||||
for (; module != NULL; module = (OSModuleInfo*)module->link.next) {
|
||||
u32 i, addr;
|
||||
OSSectionInfo* section = (OSSectionInfo*)module->info.sectionInfoOffset;
|
||||
OSSectionInfo* section = (OSSectionInfo*)module->sectionInfoOffset;
|
||||
|
||||
for (i = 0; i < module->mNumSections; section++, i++) {
|
||||
if (section->mSize != 0) {
|
||||
addr = section->mOffset & ~0x01;
|
||||
if ((addr <= (u32)address) && (u32)address < (addr + section->mSize)) {
|
||||
for (i = 0; i < module->numSections; section++, i++) {
|
||||
if (section->size != 0) {
|
||||
addr = section->offset & ~0x01;
|
||||
if ((addr <= (u32)address) && (u32)address < (addr + section->size)) {
|
||||
if (module_id != NULL)
|
||||
*module_id = module->mId;
|
||||
*module_id = module->id;
|
||||
if (section_id != NULL)
|
||||
*section_id = i;
|
||||
if (section_offset)
|
||||
*section_offset = (u32)address - addr;
|
||||
if (name_offset)
|
||||
*name_offset = module->mModuleNameOffset;
|
||||
*name_offset = module->nameOffset;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user