mirror of https://github.com/zeldaret/tp
shieldD revolution OS mostly done (#2892)
* begin revolution sdk setup * wii rvl test * revo OS mostly done for shieldD
This commit is contained in:
parent
3c1323cf0d
commit
139722c731
|
|
@ -4108,7 +4108,7 @@ revolution/os/OSPlayTime.c:
|
|||
revolution/os/OSLaunch.c:
|
||||
.text start:0x805C95C0 end:0x805C9810
|
||||
|
||||
revolution/os/__ppc_eabi_init.c:
|
||||
revolution/os/__ppc_eabi_init.cpp:
|
||||
.text start:0x805C9810 end:0x805C9920
|
||||
|
||||
revolution/exi/EXIBios.c:
|
||||
|
|
|
|||
100
configure.py
100
configure.py
|
|
@ -358,6 +358,50 @@ cflags_dolphin = [
|
|||
"-DSDK_REVISION=2",
|
||||
]
|
||||
|
||||
# Revolution library flags
|
||||
cflags_revolution_base = [
|
||||
"-nodefaults",
|
||||
"-proc gekko",
|
||||
"-align powerpc",
|
||||
"-enum int",
|
||||
"-fp hardware",
|
||||
"-Cpp_exceptions off",
|
||||
'-pragma "cats off"',
|
||||
'-pragma "warn_notinlined off"',
|
||||
"-maxerrors 1",
|
||||
"-nosyspath",
|
||||
#"-char unsigned",
|
||||
"-sym on",
|
||||
"-inline auto",
|
||||
"-ipa file",
|
||||
"-i include",
|
||||
f"-i build/{config.version}/include",
|
||||
"-ir src/revolution",
|
||||
"-i src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include",
|
||||
"-i src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common_Embedded/Math/Include",
|
||||
"-i src/PowerPC_EABI_Support/MSL/MSL_C/PPC_EABI/Include",
|
||||
"-i src/PowerPC_EABI_Support/MSL/MSL_C++/MSL_Common/Include",
|
||||
"-i src/PowerPC_EABI_Support/Runtime/Inc",
|
||||
"-i src/PowerPC_EABI_Support/MetroTRK",
|
||||
"-i include/revolution",
|
||||
f"-DVERSION={version_num}",
|
||||
"-D__GEKKO__",
|
||||
"-D__REVOLUTION_SDK__",
|
||||
]
|
||||
|
||||
cflags_revolution_retail = [
|
||||
*cflags_revolution_base,
|
||||
"-O4,p",
|
||||
"-DSDK_SEP2006",
|
||||
]
|
||||
|
||||
cflags_revolution_debug = [
|
||||
*cflags_revolution_base,
|
||||
"-opt off",
|
||||
"-DDEBUG=1",
|
||||
"-DSDK_AUG2010",
|
||||
]
|
||||
|
||||
# Framework flags
|
||||
cflags_framework = [
|
||||
*cflags_base,
|
||||
|
|
@ -426,6 +470,23 @@ def DolphinLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
|
|||
"objects": objects,
|
||||
}
|
||||
|
||||
def RevolutionLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
|
||||
if config.version == "ShieldD":
|
||||
return {
|
||||
"lib": lib_name,
|
||||
"mw_version": "Wii/1.0",
|
||||
"cflags": cflags_revolution_debug,
|
||||
"progress_category": "sdk",
|
||||
"objects": objects,
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"lib": lib_name,
|
||||
"mw_version": "GC/3.0a3",
|
||||
"cflags": cflags_revolution_retail,
|
||||
"progress_category": "sdk",
|
||||
"objects": objects,
|
||||
}
|
||||
|
||||
# Helper function for REL script objects
|
||||
def Rel(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
|
||||
|
|
@ -1391,6 +1452,45 @@ config.libs = [
|
|||
Object(MatchingFor(ALL_GCN), "dolphin/gd/GDGeometry.c"),
|
||||
],
|
||||
),
|
||||
RevolutionLib(
|
||||
"os",
|
||||
[
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OS.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSAddress.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSAlarm.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSAlloc.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSArena.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSAudioSystem.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSCache.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSContext.c"),
|
||||
Object(NonMatching, "revolution/os/OSError.c"),
|
||||
Object(NonMatching, "revolution/os/OSExec.c"),
|
||||
Object(NonMatching, "revolution/os/OSFatal.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSFont.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSInterrupt.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSLink.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSMessage.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSMemory.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSMutex.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSReboot.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSReset.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSRtc.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSStopwatch.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSSync.c"),
|
||||
Object(NonMatching, "revolution/os/OSThread.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSTime.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSUtf.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSIpc.c"),
|
||||
Object(NonMatching, "revolution/os/OSStateTM.c"),
|
||||
Object(NonMatching, "revolution/os/OSPlayRecord.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSStateFlags.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSNet.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSNandbootInfo.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSPlayTime.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/OSLaunch.c"),
|
||||
Object(MatchingFor("ShieldD"), "revolution/os/__ppc_eabi_init.cpp"),
|
||||
],
|
||||
),
|
||||
{
|
||||
"lib": "Runtime.PPCEABI.H",
|
||||
"mw_version": MWVersion(config.version),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _REVOLUTION_PPCARCH
|
||||
#define _REVOLUTION_PPCARCH
|
||||
|
||||
#include "dolphin/types.h"
|
||||
#include "revolution/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -508,6 +508,7 @@ void PPCMtpmc1(u32 newPmc1);
|
|||
void PPCMtpmc2(u32 newPmc1);
|
||||
void PPCMtpmc3(u32 newPmc1);
|
||||
void PPCMtpmc4(u32 newPmc1);
|
||||
void PPCMthid4(u32);
|
||||
void PPCMtmmcr0(u32 newMmcr0);
|
||||
void PPCMtmmcr1(u32 newMmcr0);
|
||||
void PPCMtdmaU(u32 newdmau);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define _REVOLUTION_DVD_H_
|
||||
|
||||
#include <revolution/types.h>
|
||||
#include <revolution/esp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -136,6 +137,26 @@ typedef struct DVDDriveInfo {
|
|||
/* 0x08 */ u8 padding[24];
|
||||
} DVDDriveInfo;
|
||||
|
||||
typedef struct DVDGamePartition {
|
||||
ESTicket ticket;
|
||||
u32 tmdSize;
|
||||
ESTitleMeta* tmd;
|
||||
u32 certBlobSize;
|
||||
void* certBlob;
|
||||
u8* h3Hashes;
|
||||
u8* encryptedArea;
|
||||
} DVDGamePartition;
|
||||
|
||||
typedef struct DVDPartitionInfo {
|
||||
DVDGamePartition* gamePartition;
|
||||
u32 type;
|
||||
} DVDPartitionInfo;
|
||||
|
||||
typedef struct DVDGameTOC {
|
||||
u32 numGamePartitions;
|
||||
DVDPartitionInfo* partitionInfos;
|
||||
} DVDGameTOC;
|
||||
|
||||
// DVD
|
||||
void DVDInit(void);
|
||||
int DVDReadAbsAsyncPrio(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback, s32 prio);
|
||||
|
|
@ -229,6 +250,13 @@ u32 DVDLowGetCoverStatus(void);
|
|||
// DVD QUEUE
|
||||
void DVDDumpWaitingQueue(void);
|
||||
|
||||
|
||||
// unsorted revo
|
||||
BOOL DVDLowUnencryptedRead(void*, u32, u32, DVDLowCallback);
|
||||
BOOL DVDLowClosePartition(DVDLowCallback);
|
||||
BOOL DVDLowOpenPartitionWithTmdAndTicketView(const u32, const ESTicketView* const, const u32, const ESTitleMeta* const, const u32, const u8* const, DVDLowCallback);
|
||||
BOOL DVDLowOpenPartition(const u32, const ESTicket* const, const u32, const u8* const, ESTitleMeta*, DVDLowCallback);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
#ifndef ESP_H
|
||||
#define ESP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <revolution/types.h>
|
||||
#include <revolution/private/iostypes.h>
|
||||
|
||||
typedef u32 ESId;
|
||||
typedef u32 ESContentId;
|
||||
typedef u64 ESTitleId;
|
||||
typedef u64 ESTicketId;
|
||||
typedef u8 ESVersion;
|
||||
typedef u16 ESTitleVersion;
|
||||
typedef ESTitleId ESSysVersion;
|
||||
typedef u32 ESTitleType;
|
||||
typedef u16 ESContentType;
|
||||
typedef u8 ESTmdReserved[62];
|
||||
typedef u8 ESTicketReserved[48];
|
||||
typedef u8 ESSysAccessMask[2];
|
||||
typedef u8 ESCidxMask[64];
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
typedef struct {
|
||||
ESVersion version;
|
||||
ESSysVersion sysVersion;
|
||||
ESTitleId titleId;
|
||||
ESTitleType type;
|
||||
u16 groupId;
|
||||
ESTmdReserved reserved;
|
||||
ESTitleVersion titleVersion;
|
||||
u16 numContents;
|
||||
} ESTmdViewHeader;
|
||||
|
||||
typedef struct {
|
||||
ESContentId cid;
|
||||
u16 index;
|
||||
ESContentType type;
|
||||
u64 size;
|
||||
} ESCmdView;
|
||||
|
||||
typedef struct {
|
||||
u32 code;
|
||||
u32 limit;
|
||||
} ESLpEntry;
|
||||
|
||||
typedef struct {
|
||||
ESVersion version;
|
||||
ESTicketId ticketID;
|
||||
ESId devID;
|
||||
ESTitleId titleID;
|
||||
ESSysAccessMask sysAccessMask;
|
||||
u16 ticketVer;
|
||||
u32 accTitleID;
|
||||
u32 accTitleMask;
|
||||
u8 license;
|
||||
ESTicketReserved reserved;
|
||||
u8 audit;
|
||||
ESCidxMask cidxMask;
|
||||
ESLpEntry limits[8];
|
||||
} ESTicketView;
|
||||
|
||||
typedef struct {
|
||||
ESTmdViewHeader head;
|
||||
ESCmdView contents[512];
|
||||
} ESTmdView;
|
||||
|
||||
typedef struct {
|
||||
ESContentId cid;
|
||||
u16 index;
|
||||
ESContentType type;
|
||||
u64 size;
|
||||
IOSCHash hash;
|
||||
} ESContentMeta;
|
||||
|
||||
typedef struct {
|
||||
ESVersion version;
|
||||
ESVersion caCrlVersion;
|
||||
ESVersion signerCrlVersion;
|
||||
ESSysVersion sysVersion;
|
||||
ESTitleId titleId;
|
||||
ESTitleType type;
|
||||
u16 groupId;
|
||||
ESTmdReserved reserved;
|
||||
u32 accessRights;
|
||||
ESTitleVersion titleVersion;
|
||||
u16 numContents;
|
||||
u16 bootIndex;
|
||||
} ESTitleMetaHeader;
|
||||
|
||||
typedef struct {
|
||||
IOSCSigRsa2048 sig;
|
||||
ESTitleMetaHeader head;
|
||||
ESContentMeta contents[512];
|
||||
} ESTitleMeta;
|
||||
|
||||
typedef struct {
|
||||
IOSCSigRsa2048 sig;
|
||||
IOSCEccPublicKey serverPubKey;
|
||||
ESVersion version;
|
||||
ESVersion caCrlVersion;
|
||||
ESVersion signerCrlVersion;
|
||||
IOSCAesKey titleKey;
|
||||
ESTicketId ticketId;
|
||||
ESId deviceId;
|
||||
ESTitleId titleId;
|
||||
ESSysAccessMask sysAccessMask;
|
||||
u16 ticketVersion;
|
||||
u32 accessTitleId;
|
||||
u32 accessTitleMask;
|
||||
u8 licenseType;
|
||||
ESTicketReserved reserved;
|
||||
u8 audit;
|
||||
ESCidxMask cidxMask;
|
||||
ESLpEntry limits[8];
|
||||
} ESTicket;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
s32 ESP_InitLib(void);
|
||||
s32 ESP_CloseLib(void);
|
||||
s32 ESP_LaunchTitle(u64, ESTicketView*);
|
||||
s32 ESP_GetTicketViews(ESTitleId, ESTicketView*, u32*);
|
||||
s32 ESP_DiGetTicketView(const void*, ESTicketView*);
|
||||
s32 ESP_DiGetTmd(ESTitleMeta*, u32*);
|
||||
s32 ESP_GetTmdView(ESTitleId, ESTmdView*, u32*);
|
||||
s32 ESP_GetDataDir(ESTitleId, char*);
|
||||
s32 ESP_GetTitleId(ESTitleId*);
|
||||
s32 ESP_GetConsumption(ESTicketId, ESLpEntry*, u32*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ESP_H
|
||||
|
|
@ -8,19 +8,21 @@ volatile u16 __VIRegs[59] AT_ADDRESS(0xCC002000);
|
|||
volatile u32 __PIRegs[12] AT_ADDRESS(0xCC003000);
|
||||
volatile u16 __MEMRegs[64] AT_ADDRESS(0xCC004000);
|
||||
volatile u16 __DSPRegs[] AT_ADDRESS(0xCC005000);
|
||||
volatile u32 __DIRegs[] AT_ADDRESS(0xCC006000);
|
||||
volatile u32 __DIRegs[] AT_ADDRESS(0xCD006000);
|
||||
volatile u32 __SIRegs[0x100] AT_ADDRESS(0xCC006400);
|
||||
volatile u32 __EXIRegs[0x40] AT_ADDRESS(0xCC006800);
|
||||
volatile u32 __AIRegs[8] AT_ADDRESS(0xCC006C00);
|
||||
volatile u32 __EXIRegs[0x40] AT_ADDRESS(0xCD006800);
|
||||
volatile u32 __AIRegs[8] AT_ADDRESS(0xCD006C00);
|
||||
volatile u32 __IPCRegs[4] AT_ADDRESS(0xCD000000);
|
||||
#else
|
||||
#define __VIRegs ((volatile u16 *)0xCC002000)
|
||||
#define __PIRegs ((volatile u32 *)0xCC003000)
|
||||
#define __MEMRegs ((volatile u16 *)0xCC004000)
|
||||
#define __DSPRegs ((volatile u16 *)0xCC005000)
|
||||
#define __DIRegs ((volatile u32 *)0xCC006000)
|
||||
#define __DIRegs ((volatile u32 *)0xCD006000)
|
||||
#define __SIRegs ((volatile u32 *)0xCC006400)
|
||||
#define __EXIRegs ((volatile u32 *)0xCC006800)
|
||||
#define __AIRegs ((volatile u32 *)0xCC006C00)
|
||||
#define __EXIRegs ((volatile u32 *)0xCD006800)
|
||||
#define __AIRegs ((volatile u32 *)0xCD006C00)
|
||||
#define __IPCRegs ((volatile u32 *)0xCD000000)
|
||||
#endif
|
||||
|
||||
// Offsets for __VIRegs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,167 @@
|
|||
#ifndef _REVOLUTION_NAND_H_
|
||||
#define _REVOLUTION_NAND_H_
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NAND_RESULT_OK 0
|
||||
#define NAND_RESULT_ACCESS (-1)
|
||||
#define NAND_RESULT_ALLOC_FAILED (-2)
|
||||
#define NAND_RESULT_BUSY (-3)
|
||||
#define NAND_RESULT_CORRUPT (-4)
|
||||
#define NAND_RESULT_ECC_CRIT (-5)
|
||||
#define NAND_RESULT_EXISTS (-6)
|
||||
#define NAND_RESULT_INVALID (-8)
|
||||
#define NAND_RESULT_MAXBLOCKS (-9)
|
||||
#define NAND_RESULT_MAXFD (-10)
|
||||
#define NAND_RESULT_MAXFILES (-11)
|
||||
#define NAND_RESULT_NOEXISTS (-12)
|
||||
#define NAND_RESULT_NOTEMPTY (-13)
|
||||
#define NAND_RESULT_OPENFD (-14)
|
||||
#define NAND_RESULT_AUTHENTICATION (-15)
|
||||
#define NAND_RESULT_MAXDEPTH (-16)
|
||||
#define NAND_RESULT_UNKNOWN (-64)
|
||||
#define NAND_RESULT_FATAL_ERROR (-128)
|
||||
|
||||
#define NAND_MAX_PATH 64
|
||||
|
||||
#define NAND_CHECK_HOME_INSSPACE 0x00000001
|
||||
#define NAND_CHECK_HOME_INSINODE 0x00000002
|
||||
#define NAND_CHECK_SYS_INSSPACE 0x00000004
|
||||
#define NAND_CHECK_SYS_INSINODE 0x00000008
|
||||
|
||||
typedef enum {
|
||||
NAND_ACCESS_NONE,
|
||||
NAND_ACCESS_READ,
|
||||
NAND_ACCESS_WRITE,
|
||||
NAND_ACCESS_RW
|
||||
} NANDAccessType;
|
||||
|
||||
typedef enum {
|
||||
// Read/write by owner
|
||||
NAND_PERM_RUSR = (NAND_ACCESS_READ << 4),
|
||||
NAND_PERM_WUSR = (NAND_ACCESS_WRITE << 4),
|
||||
// Read/write by group
|
||||
NAND_PERM_RGRP = (NAND_ACCESS_READ << 2),
|
||||
NAND_PERM_WGRP = (NAND_ACCESS_WRITE << 2),
|
||||
// Read/write by other
|
||||
NAND_PERM_ROTH = (NAND_ACCESS_READ << 0),
|
||||
NAND_PERM_WOTH = (NAND_ACCESS_WRITE << 0),
|
||||
// Read/write by all
|
||||
NAND_PERM_RALL = NAND_PERM_RUSR | NAND_PERM_RGRP | NAND_PERM_ROTH,
|
||||
NAND_PERM_WALL = NAND_PERM_WUSR | NAND_PERM_WGRP | NAND_PERM_WOTH,
|
||||
NAND_PERM_RWALL = NAND_PERM_RALL | NAND_PERM_WALL
|
||||
} NANDPermission;
|
||||
|
||||
typedef struct NANDFileInfo {
|
||||
s32 fileDescriptor;
|
||||
s32 origFd;
|
||||
char origPath[NAND_MAX_PATH];
|
||||
char tmpPath[NAND_MAX_PATH];
|
||||
u8 accType;
|
||||
u8 stage;
|
||||
u8 mark;
|
||||
} NANDFileInfo;
|
||||
|
||||
typedef struct NANDCommandBlock {
|
||||
void* userData;
|
||||
void* callback;
|
||||
void* fileInfo;
|
||||
void* bytes;
|
||||
void* inodes;
|
||||
void* status;
|
||||
u32 ownerId;
|
||||
u16 groupId;
|
||||
u8 nextStage;
|
||||
u32 attr;
|
||||
u32 ownerAcc;
|
||||
u32 groupAcc;
|
||||
u32 othersAcc;
|
||||
u32 num;
|
||||
char absPath[NAND_MAX_PATH];
|
||||
u32* length;
|
||||
u32* pos;
|
||||
int state;
|
||||
void* copyBuf;
|
||||
u32 bufLength;
|
||||
u8* type;
|
||||
u32 uniqNo;
|
||||
u32 reqBlocks;
|
||||
u32 reqInodes;
|
||||
u32* answer;
|
||||
u32 homeBlocks;
|
||||
u32 homeInodes;
|
||||
u32 userBlocks;
|
||||
u32 userInodes;
|
||||
u32 workBlocks;
|
||||
u32 workInodes;
|
||||
const char* *dir;
|
||||
BOOL simpleFlag;
|
||||
} NANDCommandBlock;
|
||||
|
||||
typedef struct NANDStatus {
|
||||
u32 ownerId;
|
||||
u16 groupId;
|
||||
u8 attribute;
|
||||
u8 permission;
|
||||
} NANDStatus;
|
||||
|
||||
typedef struct {
|
||||
u32 signature;
|
||||
u32 flag;
|
||||
u16 iconSpeed;
|
||||
u8 reserved[22];
|
||||
u16 comment[2][32];
|
||||
u8 bannerTexture[192 * 64 * 2];
|
||||
u8 iconTexture[8][48 * 48 * 2];
|
||||
} NANDBanner;
|
||||
|
||||
typedef void (*NANDCallback)(s32, NANDCommandBlock*);
|
||||
typedef void (*NANDAsyncCallback)(s32 result, struct NANDCommandBlock* block);
|
||||
|
||||
s32 NANDInit(void);
|
||||
|
||||
s32 NANDCreate(const char*, u8, u8);
|
||||
s32 NANDPrivateCreate(const char*, u8, u8);
|
||||
|
||||
s32 NANDOpen(const char*, NANDFileInfo*, u8);
|
||||
s32 NANDPrivateOpen(const char*, NANDFileInfo*, u8);
|
||||
s32 NANDOpenAsync(const char*, NANDFileInfo*, u8, NANDCallback, NANDCommandBlock*);
|
||||
s32 NANDPrivateOpenAsync(const char*, NANDFileInfo*, const u8, NANDCallback, NANDCommandBlock*);
|
||||
|
||||
s32 NANDClose(NANDFileInfo*);
|
||||
s32 NANDCloseAsync(NANDFileInfo*, NANDCallback, NANDCommandBlock*);
|
||||
s32 NANDRead(NANDFileInfo*, void*, u32);
|
||||
s32 NANDReadAsync(NANDFileInfo*, void*, u32, NANDCallback, NANDCommandBlock*);
|
||||
|
||||
s32 NANDGetLength(NANDFileInfo*, u32*);
|
||||
|
||||
s32 NANDDelete(const char*);
|
||||
|
||||
s32 NANDMove(const char*, const char*);
|
||||
|
||||
s32 NANDCheck(u32, u32, u32*);
|
||||
|
||||
s32 NANDWrite(NANDFileInfo*, const void*, u32);
|
||||
s32 NANDWriteAsync(NANDFileInfo*, const void*, u32, NANDCallback, NANDCommandBlock*);
|
||||
|
||||
s32 NANDSeekAsync(NANDFileInfo*, s32, s32, NANDCallback, NANDCommandBlock*);
|
||||
|
||||
s32 NANDPrivateGetStatus(const char*, NANDStatus*);
|
||||
s32 NANDPrivateDelete(const char*);
|
||||
s32 NANDPrivateCreate(const char*, u8, u8);
|
||||
|
||||
s32 NANDGetHomeDir(char[NAND_MAX_PATH]);
|
||||
|
||||
s32 NANDGetStatus(const char*, NANDStatus*);
|
||||
|
||||
s32 NANDSecretGetUsage(const char*, u32*, u32*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -42,6 +42,10 @@ typedef u32 OSTick;
|
|||
#include <revolution/os/OSSemaphore.h>
|
||||
#include <revolution/os/OSUtf.h>
|
||||
#include <revolution/os/OSTimer.h>
|
||||
#include <revolution/os/OSPlayTime.h>
|
||||
#include <revolution/os/OSStateFlags.h>
|
||||
#include <revolution/os/OSIpc.h>
|
||||
#include <revolution/os/OSNandbootInfo.h>
|
||||
|
||||
// private macro, maybe shouldn't be defined here?
|
||||
#define OFFSET(addr, align) (((u32)(addr) & ((align)-1)))
|
||||
|
|
@ -96,11 +100,20 @@ void* OSGetArenaHi(void);
|
|||
void* OSGetArenaLo(void);
|
||||
void OSSetArenaHi(void* newHi);
|
||||
void OSSetArenaLo(void* newLo);
|
||||
|
||||
void OSSetMEM1ArenaHi(void* newHi);
|
||||
void OSSetMEM1ArenaLo(void* newLo);
|
||||
void OSSetMEM2ArenaHi(void* newHi);
|
||||
void OSSetMEM2ArenaLo(void* newLo);
|
||||
|
||||
void* OSGetMEM1ArenaLo(void);
|
||||
void* OSGetMEM1ArenaHi(void);
|
||||
void* OSGetMEM2ArenaLo(void);
|
||||
void* OSGetMEM2ArenaHi(void);
|
||||
|
||||
void* OSAllocFromMEM1ArenaLo(u32 size, u32 align);
|
||||
void* OSAllocFromMEM1ArenaHi(u32 size, u32 align);
|
||||
|
||||
u32 OSGetPhysicalMemSize(void);
|
||||
|
||||
void __OSPSInit(void);
|
||||
void __OSFPRInit(void);
|
||||
u32 __OSGetDIConfig(void);
|
||||
|
|
@ -133,6 +146,16 @@ typedef struct OSBootInfo_s {
|
|||
u32 FSTMaxLength;
|
||||
} OSBootInfo;
|
||||
|
||||
typedef struct OSIOSRev {
|
||||
u8 reserved;
|
||||
u8 major;
|
||||
u8 minor;
|
||||
u8 micro;
|
||||
u8 month;
|
||||
u8 date;
|
||||
u16 year;
|
||||
} OSIOSRev;
|
||||
|
||||
typedef struct OSStopwatch {
|
||||
char* name;
|
||||
u32 hits;
|
||||
|
|
@ -187,6 +210,8 @@ BOOL OSRestoreInterrupts(BOOL level);
|
|||
u32 OSGetSoundMode(void);
|
||||
void OSSetSoundMode(u32 mode);
|
||||
|
||||
u8 OSGetAppType(void);
|
||||
|
||||
__declspec(weak) void OSReport(const char* msg, ...);
|
||||
__declspec(weak) void OSVReport(const char* msg, va_list list);
|
||||
__declspec(weak) void OSPanic(const char* file, int line, const char* msg, ...);
|
||||
|
|
@ -243,21 +268,16 @@ void* OSUncachedToCached(void* ucaddr);
|
|||
#define OSUncachedToCached(ucaddr) ((void*) ((u8*)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED)))
|
||||
#endif
|
||||
|
||||
#define OSIsMEM1Region(addr) (((u32)(addr) & 0x30000000) == 0x00000000)
|
||||
#define OSIsMEM2Region(addr) (((u32)(addr) & 0x30000000) == 0x10000000)
|
||||
|
||||
// unsorted externs
|
||||
extern OSTime __OSGetSystemTime(void);
|
||||
__declspec(weak) extern int __OSIsGcam;
|
||||
extern OSExecParams __OSRebootParams;
|
||||
extern OSTime __OSStartTime;
|
||||
extern int __OSInIPL;
|
||||
|
||||
// helper for assert line numbers in different revisions
|
||||
#if SDK_REVISION < 1
|
||||
#define LINE(l0, l1, l2) (l0)
|
||||
#elif SDK_REVISION < 2
|
||||
#define LINE(l0, l1, l2) (l1)
|
||||
#else
|
||||
#define LINE(l0, l1, l2) (l2)
|
||||
#endif
|
||||
extern BOOL __OSInReboot;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ASSERTLINE(line, cond) \
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ struct OSAlarm {
|
|||
OSAlarm* next;
|
||||
OSTime period;
|
||||
OSTime start;
|
||||
void* userData;
|
||||
};
|
||||
|
||||
BOOL OSCheckAlarmQueue(void);
|
||||
void OSInitAlarm(void);
|
||||
void OSCreateAlarm(OSAlarm* alarm);
|
||||
void OSSetAlarm(OSAlarm* alarm, OSTime tick, OSAlarmHandler handler);
|
||||
void OSSetAbsAlarm(OSAlarm* alarm, OSTime time, OSAlarmHandler handler);
|
||||
|
|
@ -28,6 +28,8 @@ void OSSetPeriodicAlarm(OSAlarm* alarm, OSTime start, OSTime period, OSAlarmHand
|
|||
void OSCancelAlarm(OSAlarm *alarm);
|
||||
void OSSetAlarmTag(OSAlarm* alarm, u32 tag);
|
||||
void OSCancelAlarms(u32 tag);
|
||||
void OSSetAlarmUserData(OSAlarm* alarm, void* userData);
|
||||
void* OSGetAlarmUserData(const OSAlarm* alarm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,61 +38,84 @@ typedef u32 OSInterruptMask;
|
|||
#define __OS_INTERRUPT_PI_VI 24
|
||||
#define __OS_INTERRUPT_PI_DEBUG 25
|
||||
#define __OS_INTERRUPT_PI_HSP 26
|
||||
#define __OS_INTERRUPT_PI_ACR 27
|
||||
#define __OS_INTERRUPT_MAX 32
|
||||
|
||||
#define OS_INTERRUPTMASK(interrupt) (0x80000000u >> (interrupt))
|
||||
|
||||
#define OS_INTERRUPTMASK_MEM_0 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0)
|
||||
#define OS_INTERRUPTMASK_MEM_1 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_1)
|
||||
#define OS_INTERRUPTMASK_MEM_2 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_2)
|
||||
#define OS_INTERRUPTMASK_MEM_3 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_3)
|
||||
#define OS_INTERRUPTMASK_MEM_ADDRESS OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_ADDRESS)
|
||||
#define OS_INTERRUPTMASK_MEM_RESET \
|
||||
(OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | \
|
||||
OS_INTERRUPTMASK_MEM_3)
|
||||
#define OS_INTERRUPTMASK_MEM \
|
||||
(OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | \
|
||||
OS_INTERRUPTMASK_MEM_3 | OS_INTERRUPTMASK_MEM_ADDRESS)
|
||||
#define OS_INTERRUPTMASK_DSP_AI OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_AI)
|
||||
#define OS_INTERRUPTMASK_DSP_ARAM OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_ARAM)
|
||||
#define OS_INTERRUPTMASK_DSP_DSP OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_DSP)
|
||||
#define OS_INTERRUPTMASK_DSP \
|
||||
(OS_INTERRUPTMASK_DSP_AI | OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP)
|
||||
#define OS_INTERRUPTMASK_AI_AI OS_INTERRUPTMASK(__OS_INTERRUPT_AI_AI)
|
||||
#define OS_INTERRUPTMASK_AI (OS_INTERRUPTMASK_AI_AI)
|
||||
#define OS_INTERRUPTMASK_EXI_0_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_0_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_0_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_0 \
|
||||
(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_1_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_1_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_1_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_1 \
|
||||
(OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_2_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_2_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_2_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_2_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_2 (OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC)
|
||||
#define OS_INTERRUPTMASK_EXI \
|
||||
(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT | \
|
||||
OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT | \
|
||||
OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC)
|
||||
#define OS_INTERRUPTMASK_PI_PE_TOKEN OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_TOKEN)
|
||||
#define OS_INTERRUPTMASK_PI_PE_FINISH OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_FINISH)
|
||||
#define OS_INTERRUPTMASK_PI_PE (OS_INTERRUPTMASK_PI_PE_TOKEN | OS_INTERRUPTMASK_PI_PE_FINISH)
|
||||
#define OS_INTERRUPTMASK_PI_CP OS_INTERRUPTMASK(__OS_INTERRUPT_PI_CP)
|
||||
#define OS_INTERRUPTMASK_PI_SI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_SI)
|
||||
#define OS_INTERRUPTMASK_PI_DI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DI)
|
||||
#define OS_INTERRUPTMASK_PI_RSW OS_INTERRUPTMASK(__OS_INTERRUPT_PI_RSW)
|
||||
#define OS_INTERRUPTMASK_PI_ERROR OS_INTERRUPTMASK(__OS_INTERRUPT_PI_ERROR)
|
||||
#define OS_INTERRUPTMASK_PI_VI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_VI)
|
||||
#define OS_INTERRUPTMASK_PI_DEBUG OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DEBUG)
|
||||
#define OS_INTERRUPTMASK_PI_HSP OS_INTERRUPTMASK(__OS_INTERRUPT_PI_HSP)
|
||||
#define OS_INTERRUPTMASK_PI \
|
||||
(OS_INTERRUPTMASK_PI_CP | OS_INTERRUPTMASK_PI_SI | OS_INTERRUPTMASK_PI_DI | \
|
||||
OS_INTERRUPTMASK_PI_RSW | OS_INTERRUPTMASK_PI_ERROR | OS_INTERRUPTMASK_PI_VI | \
|
||||
OS_INTERRUPTMASK_PI_PE_TOKEN | OS_INTERRUPTMASK_PI_PE_FINISH | OS_INTERRUPTMASK_PI_DEBUG | \
|
||||
OS_INTERRUPTMASK_PI_HSP)
|
||||
#define OS_INTERRUPTMASK_MEM_0 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0)
|
||||
#define OS_INTERRUPTMASK_MEM_1 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_1)
|
||||
#define OS_INTERRUPTMASK_MEM_2 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_2)
|
||||
#define OS_INTERRUPTMASK_MEM_3 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_3)
|
||||
#define OS_INTERRUPTMASK_MEM_ADDRESS OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_ADDRESS)
|
||||
#define OS_INTERRUPTMASK_MEM_RESET (OS_INTERRUPTMASK_MEM_0 | \
|
||||
OS_INTERRUPTMASK_MEM_1 | \
|
||||
OS_INTERRUPTMASK_MEM_2 | \
|
||||
OS_INTERRUPTMASK_MEM_3)
|
||||
#define OS_INTERRUPTMASK_MEM (OS_INTERRUPTMASK_MEM_0 | \
|
||||
OS_INTERRUPTMASK_MEM_1 | \
|
||||
OS_INTERRUPTMASK_MEM_2 | \
|
||||
OS_INTERRUPTMASK_MEM_3 | \
|
||||
OS_INTERRUPTMASK_MEM_ADDRESS)
|
||||
#define OS_INTERRUPTMASK_DSP_AI OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_AI)
|
||||
#define OS_INTERRUPTMASK_DSP_ARAM OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_ARAM)
|
||||
#define OS_INTERRUPTMASK_DSP_DSP OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_DSP)
|
||||
#define OS_INTERRUPTMASK_DSP (OS_INTERRUPTMASK_DSP_AI | \
|
||||
OS_INTERRUPTMASK_DSP_ARAM | \
|
||||
OS_INTERRUPTMASK_DSP_DSP)
|
||||
|
||||
#define OS_INTERRUPTMASK_AI_AI OS_INTERRUPTMASK(__OS_INTERRUPT_AI_AI)
|
||||
#define OS_INTERRUPTMASK_AI (OS_INTERRUPTMASK_AI_AI)
|
||||
|
||||
#define OS_INTERRUPTMASK_EXI_0_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_0_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_0_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_0 (OS_INTERRUPTMASK_EXI_0_EXI | \
|
||||
OS_INTERRUPTMASK_EXI_0_TC | \
|
||||
OS_INTERRUPTMASK_EXI_0_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_1_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_1_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_1_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_1 (OS_INTERRUPTMASK_EXI_1_EXI | \
|
||||
OS_INTERRUPTMASK_EXI_1_TC | \
|
||||
OS_INTERRUPTMASK_EXI_1_EXT)
|
||||
#define OS_INTERRUPTMASK_EXI_2_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_2_EXI)
|
||||
#define OS_INTERRUPTMASK_EXI_2_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_2_TC)
|
||||
#define OS_INTERRUPTMASK_EXI_2 (OS_INTERRUPTMASK_EXI_2_EXI | \
|
||||
OS_INTERRUPTMASK_EXI_2_TC)
|
||||
#define OS_INTERRUPTMASK_EXI (OS_INTERRUPTMASK_EXI_0_EXI | \
|
||||
OS_INTERRUPTMASK_EXI_0_TC | \
|
||||
OS_INTERRUPTMASK_EXI_0_EXT | \
|
||||
OS_INTERRUPTMASK_EXI_1_EXI | \
|
||||
OS_INTERRUPTMASK_EXI_1_TC | \
|
||||
OS_INTERRUPTMASK_EXI_1_EXT | \
|
||||
OS_INTERRUPTMASK_EXI_2_EXI | \
|
||||
OS_INTERRUPTMASK_EXI_2_TC)
|
||||
|
||||
#define OS_INTERRUPTMASK_PI_PE_TOKEN OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_TOKEN)
|
||||
#define OS_INTERRUPTMASK_PI_PE_FINISH OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_FINISH)
|
||||
#define OS_INTERRUPTMASK_PI_PE (OS_INTERRUPTMASK_PI_PE_TOKEN | \
|
||||
OS_INTERRUPTMASK_PI_PE_FINISH)
|
||||
#define OS_INTERRUPTMASK_PI_CP OS_INTERRUPTMASK(__OS_INTERRUPT_PI_CP)
|
||||
#define OS_INTERRUPTMASK_PI_SI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_SI)
|
||||
#define OS_INTERRUPTMASK_PI_DI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DI)
|
||||
#define OS_INTERRUPTMASK_PI_RSW OS_INTERRUPTMASK(__OS_INTERRUPT_PI_RSW)
|
||||
#define OS_INTERRUPTMASK_PI_ERROR OS_INTERRUPTMASK(__OS_INTERRUPT_PI_ERROR)
|
||||
#define OS_INTERRUPTMASK_PI_VI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_VI)
|
||||
#define OS_INTERRUPTMASK_PI_DEBUG OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DEBUG)
|
||||
#define OS_INTERRUPTMASK_PI_HSP OS_INTERRUPTMASK(__OS_INTERRUPT_PI_HSP)
|
||||
#define OS_INTERRUPTMASK_PI_ACR OS_INTERRUPTMASK(__OS_INTERRUPT_PI_ACR)
|
||||
#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_ACR )
|
||||
|
||||
typedef void (*__OSInterruptHandler)(__OSInterrupt interrupt, OSContext* context);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _REVOLUTION_OSIPC_H_
|
||||
#define _REVOLUTION_OSIPC_H_
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void* __OSGetIPCBufferHi(void);
|
||||
void* __OSGetIPCBufferLo(void);
|
||||
void __OSInitIPCBuffer(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _REVOLUTION_OSIPC_H_
|
||||
|
|
@ -18,8 +18,10 @@ extern "C" {
|
|||
#define OS_PROTECT_CONTROL_RDWR (OS_PROTECT_CONTROL_READ | OS_PROTECT_CONTROL_WRITE)
|
||||
|
||||
void OSProtectRange(u32 chan, void* addr, u32 nBytes, u32 control);
|
||||
u32 OSGetPhysicalMemSize(void);
|
||||
u32 OSGetConsoleSimulatedMemSize(void);
|
||||
u32 OSGetPhysicalMem1Size(void);
|
||||
u32 OSGetPhysicalMem2Size(void);
|
||||
u32 OSGetConsoleSimulatedMem1Size(void);
|
||||
u32 OSGetConsoleSimulatedMem2Size(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,10 +90,10 @@ struct OSRel {
|
|||
u32 addend;
|
||||
};
|
||||
|
||||
#define R_REVOLUTION_NOP 201 // C9h current offset += OSRel.offset
|
||||
#define R_REVOLUTION_SECTION 202 // CAh current section = OSRel.section
|
||||
#define R_REVOLUTION_END 203 // CBh
|
||||
#define R_REVOLUTION_MRKREF 204 // CCh
|
||||
#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
|
||||
|
||||
void OSSetStringTable(void* stringTable);
|
||||
BOOL OSLink(OSModuleInfo* newModule, void* bss);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef _REVOLUTION_OSNANDBOOT_H_
|
||||
#define _REVOLUTION_OSNANDBOOT_H_
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
u32 CheckSum;
|
||||
u32 ArgOffset;
|
||||
u8 reserved[2];
|
||||
u8 LastAppType;
|
||||
u8 ReturnType;
|
||||
u32 ArgValue;
|
||||
u8 padding[8];
|
||||
u64 LastTitleId;
|
||||
u8 args[0x1000];
|
||||
} OSNandbootInfo;
|
||||
|
||||
typedef struct {
|
||||
u32 CheckSum;
|
||||
u32 ArgOffset;
|
||||
u8 reserved[2];
|
||||
u8 LastAppType;
|
||||
u8 ReturnType;
|
||||
u32 ArgValue;
|
||||
u8 padding[8];
|
||||
u64 LastTitleId;
|
||||
} OSNandbootInfoHeader;
|
||||
|
||||
BOOL __OSCreateNandbootInfo(void);
|
||||
BOOL __OSWriteNandbootInfo(OSNandbootInfo*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _REVOLUTION_OSNANDBOOT_H_
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef OSPLAYRECORD_H
|
||||
#define OSPLAYRECORD_H
|
||||
|
||||
#include <revolution/os.h>
|
||||
|
||||
typedef struct {
|
||||
u32 checkSum;
|
||||
u16 titleName[2][21];
|
||||
OSTime playStartTime;
|
||||
OSTime playTime;
|
||||
char gameCode[4];
|
||||
char companyCode[2];
|
||||
char res[18];
|
||||
} OSPlayRecord;
|
||||
|
||||
void __OSStartPlayRecord(void);
|
||||
void __OSStopPlayRecord(void);
|
||||
|
||||
#endif // OSPLAYRECORD_H
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef _REVOLUTION_OSPLAYTIME_H_
|
||||
#define _REVOLUTION_OSPLAYTIME_H_
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
OSPLAYTIME_PERMANENT = 0,
|
||||
OSPLAYTIME_LIMITED = 1,
|
||||
OSPLAYTIME_LIMITED_LAUNCH = 4,
|
||||
OSPLAYTIME_OTHER = 9
|
||||
} __OSPlayTimeType;
|
||||
|
||||
typedef void (*OSPlayTimeCallbackFunc)(void);
|
||||
|
||||
BOOL OSPlayTimeIsLimited(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -11,26 +11,30 @@ extern "C" {
|
|||
#define OS_RESET_HOTRESET 1
|
||||
#define OS_RESET_SHUTDOWN 2
|
||||
|
||||
typedef struct OSResetFunctionInfo OSResetFunctionInfo;
|
||||
typedef struct OSResetFunctionQueue {
|
||||
OSResetFunctionInfo* head;
|
||||
OSResetFunctionInfo* tail;
|
||||
} OSResetFunctionQueue;
|
||||
typedef struct OSShutdownFunctionInfo OSShutdownFunctionInfo;
|
||||
typedef struct OSShutdownFunctionQueue {
|
||||
OSShutdownFunctionInfo* head;
|
||||
OSShutdownFunctionInfo* tail;
|
||||
} OSShutdownFunctionQueue;
|
||||
|
||||
typedef BOOL (*OSResetFunction)(BOOL);
|
||||
typedef BOOL (*OSResetFunction)(BOOL, u32);
|
||||
|
||||
struct OSResetFunctionInfo {
|
||||
struct OSShutdownFunctionInfo {
|
||||
OSResetFunction func;
|
||||
u32 priority;
|
||||
OSResetFunctionInfo* next;
|
||||
OSResetFunctionInfo* prev;
|
||||
OSShutdownFunctionInfo* next;
|
||||
OSShutdownFunctionInfo* prev;
|
||||
};
|
||||
|
||||
void OSRegisterResetFunction(OSResetFunctionInfo* info);
|
||||
void OSUnregisterResetFunction(OSResetFunctionInfo* info);
|
||||
void OSRegisterShutdownFunction(OSShutdownFunctionInfo* info);
|
||||
void OSUnregisterShutdownFunction(OSShutdownFunctionInfo* info);
|
||||
void OSResetSystem(int reset, u32 resetCode, BOOL forceMenu);
|
||||
u32 OSGetResetCode();
|
||||
u32 OSSetBootDol(u32 dolOffset);
|
||||
void OSReturnToMenu(void);
|
||||
|
||||
#define OSIsRestart() \
|
||||
((OSGetResetCode() & 0x80000000) ? TRUE : FALSE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
typedef void (*OSResetCallback)(void);
|
||||
typedef void (*OSPowerCallback)(void);
|
||||
|
||||
OSResetCallback OSSetResetCallback(OSResetCallback callback);
|
||||
BOOL OSGetResetSwitchState(void);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _REVOLUTION_OSSTATEFLAGS_H_
|
||||
#define _REVOLUTION_OSSTATEFLAGS_H_
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
u32 checkSum;
|
||||
u8 lastBootApp;
|
||||
u8 lastShutdown;
|
||||
u8 lastDiscState;
|
||||
u8 menuMode;
|
||||
u8 reserved[24];
|
||||
} OSStateFlags;
|
||||
|
||||
BOOL __OSWriteStateFlags(OSStateFlags*);
|
||||
BOOL __OSReadStateFlags(OSStateFlags*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OSSTATEFLAGS_H
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <revolution/private/iosrestypes.h>
|
||||
#include <revolution/private/iostypes.h>
|
||||
#include <revolution/types.h>
|
||||
|
||||
typedef IOSError (*IOSIpcCb) (IOSError, void *);
|
||||
|
||||
s32 IOS_Read(s32, void*, u32);
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
#pragma once
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
typedef u32 IOSUid;
|
||||
typedef u16 IOSGid;
|
||||
typedef u32 IOSResourceHandle;
|
||||
|
||||
#define IOS_ERROR_OK 0
|
||||
#define IOS_ERROR_ACCESS -1
|
||||
#define IOS_ERROR_EXISTS -2
|
||||
#define IOS_ERROR_INTR -3
|
||||
#define IOS_ERROR_INVALID -4
|
||||
#define IOS_ERROR_MAX -5
|
||||
#define IOS_ERROR_NOEXISTS -6
|
||||
#define IOS_ERROR_QEMPTY -7
|
||||
#define IOS_ERROR_QFULL -8
|
||||
#define IOS_ERROR_UNKNOWN -9
|
||||
#define IOS_ERROR_NOTREADY -10
|
||||
#define IOS_ERROR_ECC -11
|
||||
#define IOS_ERROR_ECC_CRIT -12
|
||||
#define IOS_ERROR_BADBLOCK -13
|
||||
|
||||
#define IOS_ERROR_INVALID_OBJTYPE -14
|
||||
#define IOS_ERROR_INVALID_RNG -15
|
||||
#define IOS_ERROR_INVALID_FLAG -16
|
||||
#define IOS_ERROR_INVALID_FORMAT -17
|
||||
#define IOS_ERROR_INVALID_VERSION -18
|
||||
#define IOS_ERROR_INVALID_SIGNER -19
|
||||
#define IOS_ERROR_FAIL_CHECKVALUE -20
|
||||
#define IOS_ERROR_FAIL_INTERNAL -21
|
||||
#define IOS_ERROR_FAIL_ALLOC -22
|
||||
#define IOS_ERROR_INVALID_SIZE -23
|
||||
|
||||
typedef struct {
|
||||
u8 *path;
|
||||
u32 flags;
|
||||
IOSUid uid;
|
||||
IOSGid gid;
|
||||
} IOSResourceOpen;
|
||||
|
||||
typedef struct {
|
||||
u8 *outPtr;
|
||||
u32 outLen;
|
||||
} IOSResourceRead;
|
||||
|
||||
typedef struct {
|
||||
u8 *inPtr;
|
||||
u32 inLen;
|
||||
} IOSResourceWrite;
|
||||
|
||||
typedef struct {
|
||||
s32 offset;
|
||||
u32 whence;
|
||||
} IOSResourceSeek;
|
||||
|
||||
typedef struct {
|
||||
u32 cmd;
|
||||
u8 *inPtr;
|
||||
u32 inLen;
|
||||
u8 *outPtr;
|
||||
u32 outLen;
|
||||
} IOSResourceIoctl;
|
||||
|
||||
typedef struct {
|
||||
u8 *base;
|
||||
u32 length;
|
||||
} IOSIoVector;
|
||||
|
||||
typedef struct {
|
||||
u32 cmd;
|
||||
u32 readCount;
|
||||
u32 writeCount;
|
||||
IOSIoVector *vector;
|
||||
} IOSResourceIoctlv;
|
||||
|
||||
typedef struct {
|
||||
u32 cmd;
|
||||
s32 status;
|
||||
IOSResourceHandle handle;
|
||||
union {
|
||||
IOSResourceOpen open;
|
||||
IOSResourceRead read;
|
||||
IOSResourceWrite write;
|
||||
IOSResourceSeek seek;
|
||||
IOSResourceIoctl ioctl;
|
||||
IOSResourceIoctlv ioctlv;
|
||||
} args;
|
||||
} IOSResourceRequest;
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
typedef s32 IOSError;
|
||||
typedef s32 IOSCid;
|
||||
typedef s32 IOSFd;
|
||||
typedef s32 IOSMessageQueueId;
|
||||
typedef s32 IOSMessage;
|
||||
typedef s32 IOSTimerId;
|
||||
typedef s32 IOSHeapId;
|
||||
typedef s32 IOSThreadId;
|
||||
typedef s32 IOSProcessId;
|
||||
typedef s32 IOSInterfaceId;
|
||||
typedef u32 IOSTime;
|
||||
typedef u32 IOSEvent;
|
||||
|
||||
typedef u8 IOSCName[64];
|
||||
typedef u8 IOSCSigDummy[60];
|
||||
typedef u8 IOSCHash[20];
|
||||
|
||||
typedef u8 CSLOSEccPublicKey[60];
|
||||
typedef u8 CSLOSRsaSig2048[256];
|
||||
|
||||
typedef u8 CSLOSAesKey[16];
|
||||
|
||||
typedef CSLOSEccPublicKey IOSCEccPublicKey;
|
||||
typedef CSLOSRsaSig2048 IOSCRsaSig2048;
|
||||
|
||||
typedef CSLOSAesKey IOSCAesKey;
|
||||
|
||||
typedef enum {
|
||||
IOSC_SIG_RSA4096 = 0x00010000,
|
||||
IOSC_SIG_RSA2048,
|
||||
IOSC_SIG_ECC
|
||||
} IOSCCertSigType;
|
||||
|
||||
typedef struct {
|
||||
IOSCCertSigType sigType;
|
||||
IOSCRsaSig2048 sig;
|
||||
IOSCSigDummy dummy;
|
||||
IOSCName issuer;
|
||||
} IOSCSigRsa2048;
|
||||
|
|
@ -1,31 +1,141 @@
|
|||
#ifndef _REVOLUTION_SC_H_
|
||||
#define _REVOLUTION_SC_H_
|
||||
|
||||
#include <revolution/types.h>
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/nand.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef u8 SCType;
|
||||
|
||||
typedef struct {
|
||||
u8 mode;
|
||||
u8 led;
|
||||
} SCIdleModeInfo;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
u8 type_u8;
|
||||
s8 type_s8;
|
||||
u16 type_u16;
|
||||
s16 type_s16;
|
||||
u32 type_u32;
|
||||
s32 type_s32;
|
||||
u64 type_u64;
|
||||
s64 type_s64;
|
||||
u8 longPrecision64[sizeof(u64)];
|
||||
} integer;
|
||||
|
||||
SCType typeInteger;
|
||||
SCType typeByteArray;
|
||||
u32 nameLen;
|
||||
u32 dataSize;
|
||||
char* name;
|
||||
u8* data;
|
||||
u32 packedSize;
|
||||
} SCItem;
|
||||
|
||||
typedef void (*SCReloadConfFileCallback)(s32 result);
|
||||
typedef void (*SCFlushCallback)(u32 result);
|
||||
|
||||
typedef enum {
|
||||
SC_ITEM_ID_IPL_COUNTER_BIAS,
|
||||
SC_ITEM_ID_IPL_ASPECT_RATIO,
|
||||
SC_ITEM_ID_IPL_AUTORUN_MODE,
|
||||
SC_ITEM_ID_IPL_CONFIG_DONE,
|
||||
SC_ITEM_ID_IPL_CONFIG_DONE2,
|
||||
SC_ITEM_ID_IPL_DISPLAY_OFFSET_H,
|
||||
SC_ITEM_ID_IPL_EURGB60_MODE,
|
||||
SC_ITEM_ID_IPL_EULA,
|
||||
SC_ITEM_ID_IPL_FREE_CHANNEL_APP_COUNT,
|
||||
SC_ITEM_ID_IPL_IDLE_MODE,
|
||||
SC_ITEM_ID_IPL_INSTALLED_CHANNEL_APP_COUNT,
|
||||
SC_ITEM_ID_IPL_LANGUAGE,
|
||||
SC_ITEM_ID_IPL_OWNER_NICKNAME,
|
||||
SC_ITEM_ID_IPL_PARENTAL_CONTROL,
|
||||
SC_ITEM_ID_IPL_PROGRESSIVE_MODE,
|
||||
SC_ITEM_ID_IPL_SCREEN_SAVER_MODE,
|
||||
SC_ITEM_ID_IPL_SIMPLE_ADDRESS,
|
||||
SC_ITEM_ID_IPL_SOUND_MODE,
|
||||
SC_ITEM_ID_IPL_UPDATE_TYPE,
|
||||
SC_ITEM_ID_NET_CONFIG,
|
||||
SC_ITEM_ID_NET_CONTENT_RESTRICTIONS,
|
||||
SC_ITEM_ID_NET_PROFILE,
|
||||
SC_ITEM_ID_NET_WC_RESTRICTION,
|
||||
SC_ITEM_ID_NET_WC_FLAGS,
|
||||
SC_ITEM_ID_DEV_BOOT_MODE,
|
||||
SC_ITEM_ID_DEV_VIDEO_MODE,
|
||||
SC_ITEM_ID_DEV_COUNTRY_CODE,
|
||||
SC_ITEM_ID_DEV_DRIVESAVING_MODE,
|
||||
SC_ITEM_ID_BT_DEVICE_INFO,
|
||||
SC_ITEM_ID_BT_CMPDEV_INFO,
|
||||
SC_ITEM_ID_BT_DPD_SENSIBILITY,
|
||||
SC_ITEM_ID_BT_SPEAKER_VOLUME,
|
||||
SC_ITEM_ID_BT_MOTOR_MODE,
|
||||
SC_ITEM_ID_BT_SENSOR_BAR_POSITION,
|
||||
SC_ITEM_ID_DVD_CONFIG,
|
||||
SC_ITEM_ID_WWW_RESTRICTION,
|
||||
SC_ITEM_ID_MAX_PLUS1
|
||||
} SCItemID;
|
||||
|
||||
typedef struct {
|
||||
OSThreadQueue threadQueue;
|
||||
NANDFileInfo nandFileInfo;
|
||||
NANDCommandBlock nandCommandBlock;
|
||||
|
||||
union {
|
||||
u8 nandType;
|
||||
NANDStatus nandStatus;
|
||||
} u;
|
||||
|
||||
u8 nandStep;
|
||||
u8 nandNeedClose;
|
||||
u8 reloadFileCount;
|
||||
SCReloadConfFileCallback reloadCallback;
|
||||
s32 reloadResult;
|
||||
const char* reloadFileName[2];
|
||||
u8* reloadBufp[2];
|
||||
u32 reloadSizeExpected[2];
|
||||
u32 reloadedSize[2];
|
||||
SCFlushCallback flushCallback;
|
||||
u32 flushResult;
|
||||
u32 flushSize;
|
||||
} SCControl;
|
||||
|
||||
|
||||
|
||||
#define SC_LANG_JAPANESE 0u
|
||||
#define SC_LANG_ENGLISH 1u
|
||||
#define SC_LANG_GERMAN 2u
|
||||
#define SC_LANG_FRENCH 3u
|
||||
#define SC_LANG_SPANISH 4u
|
||||
#define SC_LANG_ITALIAN 5u
|
||||
#define SC_LANG_DUTCH 6u
|
||||
#define SC_LANG_SIMP_CHINESE 7u
|
||||
#define SC_LANG_TRAD_CHINESE 8u
|
||||
#define SC_LANG_KOREAN 9u
|
||||
|
||||
void SCInit(void);
|
||||
u32 SCCheckStatus(void);
|
||||
int SCReloadConfFileAsync(void* bufp, u32 bufSize, int);
|
||||
BOOL SCFindByteArrayItem(u8* data, u32, u32 itemID);
|
||||
BOOL SCFindIntegerItem(int* data, u32 itemID, u8 type);
|
||||
BOOL SCFindU8Item(u8* data, u32 itemID);
|
||||
BOOL SCFindS8Item(s8* data, u32 itemID);
|
||||
BOOL SCFindU32Item(u32* data, u32 itemID);
|
||||
s32 SCReloadConfFileAsync(u8* bufp, u32 bufSize, SCReloadConfFileCallback);
|
||||
BOOL SCFindByteArrayItem(void* data, u32, SCItemID itemID);
|
||||
BOOL SCFindIntegerItem(int* data, SCItemID itemID, u8 type);
|
||||
BOOL SCFindU8Item(u8* data, SCItemID itemID);
|
||||
BOOL SCFindS8Item(s8* data, SCItemID itemID);
|
||||
BOOL SCFindU32Item(u32* data, SCItemID itemID);
|
||||
u8 SCGetAspectRatio(void);
|
||||
u8 SCGetDisplayOffsetH(void);
|
||||
BOOL SCGetIdleMode(u8* data);
|
||||
s8 SCGetDisplayOffsetH(void);
|
||||
BOOL SCGetIdleMode(SCIdleModeInfo* data);
|
||||
u8 SCGetLanguage(void);
|
||||
u8 SCGetProgressiveMode(void);
|
||||
u8 SCGetScreenSaverMode(void);
|
||||
u8 SCGetSoundMode(void);
|
||||
u8 SCGetCounterBias(void);
|
||||
u32 SCGetCounterBias(void);
|
||||
BOOL SCGetProductAreaString(const char*, int);
|
||||
u32 SCGetProductArea(void);
|
||||
u32 SCGetProductGameRegion(void);
|
||||
s8 SCGetProductArea(void);
|
||||
s8 SCGetProductGameRegion(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef _DOLPHIN_DVD_INTERNAL_H_
|
||||
#define _DOLPHIN_DVD_INTERNAL_H_
|
||||
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/dvd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// DVD
|
||||
DVDCommandChecker __DVDSetOptionalCommandChecker(DVDCommandChecker func);
|
||||
void __DVDSetImmCommand(u32 command);
|
||||
void __DVDSetDmaCommand(u32 command);
|
||||
void* __DVDGetIssueCommandAddr(void);
|
||||
void __DVDAudioBufferConfig(DVDCommandBlock* block, u32 enable, u32 size, DVDCBCallback callback);
|
||||
void __DVDPrepareResetAsync(DVDCBCallback callback);
|
||||
int __DVDTestAlarm(const OSAlarm* alarm);
|
||||
|
||||
// DVD ERROR
|
||||
void __DVDStoreErrorCode(u32 error);
|
||||
|
||||
// DVD FATAL
|
||||
void __DVDPrintFatalMessage(void);
|
||||
|
||||
// DVD FS
|
||||
extern OSThreadQueue __DVDThreadQueue;
|
||||
extern u32 __DVDLongFileNameFlag;
|
||||
|
||||
void __DVDFSInit(void);
|
||||
|
||||
// DVD LOW
|
||||
void __DVDInitWA(void);
|
||||
void __DVDInterruptHandler(__OSInterrupt interrupt, OSContext* context);
|
||||
void __DVDLowSetWAType(u32 type, s32 seekLoc);
|
||||
int __DVDLowTestAlarm(const OSAlarm* alarm);
|
||||
|
||||
// DVD QUEUE
|
||||
void __DVDClearWaitingQueue(void);
|
||||
int __DVDPushWaitingQueue(s32 prio, DVDCommandBlock* block);
|
||||
DVDCommandBlock* __DVDPopWaitingQueue(void);
|
||||
int __DVDCheckWaitingQueue(void);
|
||||
int __DVDDequeueWaitingQueue(DVDCommandBlock* block);
|
||||
int __DVDIsBlockInWaitingQueue(DVDCommandBlock* block);
|
||||
|
||||
// FST LOAD
|
||||
void __fstLoad(void);
|
||||
|
||||
// unsorted
|
||||
u32 __DVDGetCoverStatus(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _DOLPHIN_DVD_INTERNAL_H_
|
||||
|
|
@ -0,0 +1,966 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/exi.h>
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/si.h>
|
||||
#include <revolution/db.h>
|
||||
#include <revolution/sc.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
#define NOP 0x60000000
|
||||
|
||||
// external functions
|
||||
extern void EnableMetroTRKInterrupts(void);
|
||||
extern void __OSInitMemoryProtection(void);
|
||||
extern void IPCCltInit(void);
|
||||
extern BOOL __DVDCheckDevice(void);
|
||||
|
||||
#define DB_EXCEPTIONRET_OFFSET 0xC
|
||||
#define DB_EXCEPTIONDEST_OFFSET 0x8
|
||||
#define OS_CURRENTCONTEXT_PADDR 0x00C0
|
||||
#define OS_EXCEPTIONTABLE_ADDR 0x3000
|
||||
#define OS_DBJUMPPOINT_ADDR 0x60
|
||||
|
||||
#ifdef SDK_AUG2010
|
||||
#define BUILD_DATE "Aug 23 2010"
|
||||
#define BUILD_TIME "17:27:45"
|
||||
#elif SDK_SEP2006
|
||||
#define BUILD_DATE "Sep 21 2006"
|
||||
#define BUILD_TIME "14:32:13"
|
||||
#endif
|
||||
|
||||
#ifdef SDK_AUG2010
|
||||
const char* __OSVersion = "<< RVL_SDK - OS \tdebug build: "BUILD_DATE" "BUILD_TIME" (0x4302_145) >>";
|
||||
#elif SDK_SEP2006
|
||||
const char* __OSVersion = "<< RVL_SDK - OS \trelease build: "BUILD_DATE" "BUILD_TIME" (0x4200_60422) >>";
|
||||
#endif
|
||||
|
||||
static DVDDriveInfo DriveInfo;
|
||||
static DVDCommandBlock DriveBlock;
|
||||
OSExecParams __OSRebootParams;
|
||||
|
||||
#ifdef SDK_SEP2006
|
||||
static char GameNameBuffer[5];
|
||||
#endif
|
||||
|
||||
extern u32 __DVDLongFileNameFlag;
|
||||
extern u32 __PADSpec;
|
||||
|
||||
// defined in link script
|
||||
extern u8 __ArenaLo[];
|
||||
extern char _stack_addr[];
|
||||
extern u8 __ArenaHi[];
|
||||
|
||||
OSTime __OSStartTime;
|
||||
|
||||
static OSBootInfo* BootInfo;
|
||||
static u32* BI2DebugFlag;
|
||||
static u32 BI2DebugFlagHolder;
|
||||
|
||||
void (**OSExceptionTable)(u8, OSContext*);
|
||||
BOOL AreWeInitialized;
|
||||
f32 ZeroPS[2];
|
||||
f64 ZeroF;
|
||||
BOOL __OSIsGcam;
|
||||
BOOL __OSInNandBoot;
|
||||
BOOL __OSInIPL;
|
||||
|
||||
// prototypes
|
||||
static void __OSInitFPRs(void);
|
||||
static void OSExceptionInit(void);
|
||||
|
||||
// dummy entry points to the OS Exception vector
|
||||
void __OSEVStart(void);
|
||||
void __OSEVEnd(void);
|
||||
void __OSEVSetNumber(void);
|
||||
void __OSExceptionVector(void);
|
||||
void __DBVECTOR(void);
|
||||
void __OSDBINTSTART(void);
|
||||
void __OSDBINTEND(void);
|
||||
void __OSDBJUMPSTART(void);
|
||||
void __OSDBJUMPEND(void);
|
||||
|
||||
/* clang-format off */
|
||||
#ifdef __GEKKO__
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
||||
static void DisableWriteGatherPipe(void) {
|
||||
u32 hid2;
|
||||
|
||||
hid2 = PPCMfhid2();
|
||||
hid2 &= ~0x40000000;
|
||||
PPCMthid2(hid2);
|
||||
}
|
||||
|
||||
u32 __OSGetHollywoodRev(void) {
|
||||
return *(u32*)OSPhysicalToCached(0x3138);
|
||||
}
|
||||
|
||||
void __OSGetIOSRev(OSIOSRev* rev) {
|
||||
u32 iosVer, iosBuild;
|
||||
iosVer = *(u32*)OSPhysicalToUncached(0x3140);
|
||||
iosBuild = *(u32*)OSPhysicalToUncached(0x3144);
|
||||
|
||||
rev->reserved = ((iosVer >> 24) & 0xFF);
|
||||
rev->major = ((iosVer >> 16) & 0xFF);
|
||||
rev->minor = ((iosVer >> 8) & 0xFF);
|
||||
rev->micro = (iosVer & 0xFF);
|
||||
|
||||
rev->month = (((iosBuild >> 20) & 0xF) * 10 + ((iosBuild >> 16) & 0xF));
|
||||
rev->date = (((iosBuild >> 12) & 0xF) * 10 + ((iosBuild >> 8) & 0xF));
|
||||
rev->year = (((iosBuild >> 4) & 0xF) * 10 + (iosBuild & 0xF) + 2000);
|
||||
}
|
||||
|
||||
// needed for assert
|
||||
#undef NULL
|
||||
#define NULL 0
|
||||
|
||||
u32 OSGetConsoleType(void) {
|
||||
u32 hwRev;
|
||||
u32 gddrSize;
|
||||
|
||||
if (BootInfo == NULL || BootInfo->consoleType == 0) {
|
||||
return 0x10000002;
|
||||
}
|
||||
|
||||
hwRev = __OSGetHollywoodRev();
|
||||
|
||||
if (__OSDeviceCode & 0x8000) {
|
||||
switch (__OSDeviceCode & ~0x8000) {
|
||||
case 2:
|
||||
case 3:
|
||||
case 0x203:
|
||||
switch (hwRev) {
|
||||
case 0:
|
||||
return 0x10;
|
||||
case 1:
|
||||
return 0x11;
|
||||
case 2:
|
||||
return 0x12;
|
||||
case 0x10:
|
||||
return 0x20;
|
||||
case 0x11:
|
||||
return 0x21;
|
||||
}
|
||||
|
||||
if (hwRev > 0x11) {
|
||||
return 0x21;
|
||||
}
|
||||
|
||||
case 0x202:
|
||||
case 0x201:
|
||||
switch (hwRev) {
|
||||
case 0:
|
||||
return 0x10000010;
|
||||
case 1:
|
||||
return 0x10000011;
|
||||
case 2:
|
||||
return 0x10000012;
|
||||
case 0x10:
|
||||
return 0x10000020;
|
||||
case 0x11:
|
||||
return 0x10000021;
|
||||
}
|
||||
|
||||
if (hwRev > 0x11) {
|
||||
return 0x10000021;
|
||||
}
|
||||
|
||||
#if SDK_AUG2010
|
||||
case 0x300:
|
||||
return 0x100;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gddrSize = OSGetPhysicalMem2Size();
|
||||
|
||||
switch (hwRev) {
|
||||
case 0:
|
||||
if (gddrSize == 0x4000000) {
|
||||
return 0x10;
|
||||
}
|
||||
else {
|
||||
return 0x10000010;
|
||||
}
|
||||
|
||||
case 0x1:
|
||||
if (gddrSize == 0x4000000) {
|
||||
return 0x11;
|
||||
}
|
||||
else {
|
||||
return 0x10000011;
|
||||
}
|
||||
|
||||
case 0x2:
|
||||
if (gddrSize == 0x4000000) {
|
||||
return 0x12;
|
||||
}
|
||||
else {
|
||||
return 0x10000012;
|
||||
}
|
||||
|
||||
case 0x10:
|
||||
if (gddrSize == 0x4000000) {
|
||||
return 0x20;
|
||||
}
|
||||
else {
|
||||
return 0x10000020;
|
||||
}
|
||||
|
||||
case 0x11:
|
||||
if (gddrSize == 0x4000000) {
|
||||
return 0x21;
|
||||
}
|
||||
else {
|
||||
return 0x10000021;
|
||||
}
|
||||
}
|
||||
|
||||
if (hwRev > 0x11) {
|
||||
if (gddrSize == 0x4000000) {
|
||||
return 0x21;
|
||||
}
|
||||
else {
|
||||
return 0x10000021;
|
||||
}
|
||||
}
|
||||
|
||||
return BootInfo->consoleType;
|
||||
}
|
||||
|
||||
static void MemClear(void* base, u32 size) {
|
||||
void* lastBase = (size > 0x40000) ? (void*)((u32)base + size - 0x40000) : base;
|
||||
DCZeroRange(base, size);
|
||||
DCFlushRange(lastBase, 0x40000);
|
||||
}
|
||||
|
||||
static void ClearArena(void) {
|
||||
if (!OSIsRestart()) {
|
||||
MemClear(OSGetArenaLo(), (u32)OSGetArenaHi() - (u32)OSGetArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
if (__OSRebootParams.regionStart == NULL || !OSIsMEM1Region((void*)__OSRebootParams.regionStart)) {
|
||||
MemClear(OSGetArenaLo(), (u32)OSGetArenaHi() - (u32)OSGetArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERTLINE(1068, __OSRebootParams.regionEnd != NULL);
|
||||
|
||||
if ((u32)OSGetArenaLo() < (u32)__OSRebootParams.regionStart) {
|
||||
if ((u32)OSGetArenaHi() <= (u32)__OSRebootParams.regionStart) {
|
||||
MemClear(OSGetArenaLo(), (u32)OSGetArenaHi() - (u32)OSGetArenaLo());
|
||||
} else {
|
||||
MemClear(OSGetArenaLo(), (u32)__OSRebootParams.regionStart - (u32)OSGetArenaLo());
|
||||
|
||||
if ((u32)OSGetArenaHi() > (u32)__OSRebootParams.regionEnd) {
|
||||
MemClear(__OSRebootParams.regionEnd, (u32)OSGetArenaHi() - (u32)__OSRebootParams.regionEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ClearMEM2Arena(void) {
|
||||
if (!OSIsRestart()) {
|
||||
MemClear(OSGetMEM2ArenaLo(), (u32)OSGetMEM2ArenaHi() - (u32)OSGetMEM2ArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
if (__OSRebootParams.regionStart == NULL || !OSIsMEM2Region((void*)__OSRebootParams.regionStart)) {
|
||||
MemClear(OSGetMEM2ArenaLo(), (u32)OSGetMEM2ArenaHi() - (u32)OSGetMEM2ArenaLo());
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERTLINE(1106, __OSRebootParams.regionEnd != NULL);
|
||||
|
||||
if ((u32)OSGetMEM2ArenaLo() < (u32)__OSRebootParams.regionStart) {
|
||||
if ((u32)OSGetMEM2ArenaHi() <= (u32)__OSRebootParams.regionStart) {
|
||||
MemClear(OSGetMEM2ArenaLo(), (u32)OSGetMEM2ArenaHi() - (u32)OSGetMEM2ArenaLo());
|
||||
} else {
|
||||
MemClear(OSGetMEM2ArenaLo(), (u32)__OSRebootParams.regionStart - (u32)OSGetMEM2ArenaLo());
|
||||
|
||||
if ((u32)OSGetMEM2ArenaHi() > (u32)__OSRebootParams.regionEnd) {
|
||||
MemClear(__OSRebootParams.regionEnd, (u32)OSGetMEM2ArenaHi() - (u32)__OSRebootParams.regionEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void InquiryCallback(s32, DVDCommandBlock* block) {
|
||||
switch (block->state) {
|
||||
case 0:
|
||||
__OSDeviceCode = (u16)(0x8000 | DriveInfo.deviceCode);
|
||||
break;
|
||||
default:
|
||||
__OSDeviceCode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckTargets(void) {
|
||||
switch (*(u8*)OSPhysicalToCached(0x315C)) {
|
||||
case 0x80:
|
||||
break;
|
||||
case 0x81:
|
||||
OSReport("OS ERROR: boot program is not for RVL target. Please use correct boot program.\n");
|
||||
OSPanic(__FILE__, 1160, "Failed to run app");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (*(u8*)OSPhysicalToCached(0x315D)) {
|
||||
case 0x80:
|
||||
break;
|
||||
case 0x81:
|
||||
OSReport("OS ERROR: apploader[D].img is not for RVL target. Please use correct apploader[D].img.\n");
|
||||
OSPanic(__FILE__, 1178, "Failed to run app");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SDK_AUG2010
|
||||
static void CheckFirmare(void) {
|
||||
OSIOSRev iosRev;
|
||||
u32 firmware;
|
||||
GXColor bg = {0x00, 0x00, 0xFF, 0x00};
|
||||
GXColor fg = {0xFF, 0xFF, 0xFF, 0x00};
|
||||
|
||||
__OSGetIOSRev(&iosRev);
|
||||
firmware = iosRev.major << 0x10;
|
||||
firmware |= iosRev.minor << 0x8;
|
||||
firmware |= iosRev.micro;
|
||||
|
||||
if (iosRev.major != (*(u32*)0x80003188 >> 0x10) || (iosRev.major == (*(u32*)0x80003188 >> 0x10) && firmware < *(u32*)0x80003188)) {
|
||||
OSReport("OS ERROR: This firmware is an improper version for this SDK. Please use a correct Firmware.\n");
|
||||
OSFatal(fg, bg, "\n\nERROR #002\nAn error has occurred.\nPress the Eject Button, remove the\nGame Disc, and turn off the power to \nthe console. \nPlease read the Wii Operations Manual \nfor further instructions.\n");
|
||||
OSPanic(__FILE__, 1243, "Failed to run app");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ReportOSInfo(void) {
|
||||
u32 consoleType;
|
||||
u32 sysMemSize;
|
||||
OSIOSRev ios;
|
||||
|
||||
OSReport("\nRevolution OS\n");
|
||||
OSReport("Kernel built : %s %s\n", BUILD_DATE, BUILD_TIME);
|
||||
OSReport("Console Type : " );
|
||||
|
||||
consoleType = OSGetConsoleType();
|
||||
|
||||
switch (consoleType & 0xF0000000) {
|
||||
case 0:
|
||||
switch (consoleType) {
|
||||
case 0x11:
|
||||
OSReport("Pre-production board 1\n");
|
||||
break;
|
||||
case 0x12:
|
||||
OSReport("Pre-production board 2-1\n");
|
||||
break;
|
||||
case 0x20:
|
||||
OSReport("Pre-production board 2-2\n");
|
||||
break;
|
||||
#if SDK_AUG2010
|
||||
case 0x100:
|
||||
OSReport("RVA 1\n");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
OSReport("Retail %d\n", consoleType);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x10000000:
|
||||
switch (consoleType) {
|
||||
case 0x10000021:
|
||||
OSReport("NDEV 2.1\n");
|
||||
break;
|
||||
case 0x10000020:
|
||||
OSReport("NDEV 2.0\n");
|
||||
break;
|
||||
case 0x10000012:
|
||||
OSReport("NDEV 1.2\n");
|
||||
break;
|
||||
case 0x10000011:
|
||||
OSReport("NDEV 1.1\n");
|
||||
break;
|
||||
case 0x10000010:
|
||||
OSReport("NDEV 1.0\n");
|
||||
break;
|
||||
case 0x10000008:
|
||||
OSReport("Revolution Emulator\n");
|
||||
break;
|
||||
default:
|
||||
OSReport("Emulation platform (%08x)\n", consoleType);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x20000000:
|
||||
OSReport("TDEV-based emulation HW%d\n", (consoleType & ~0xF0000000) - 3);
|
||||
break;
|
||||
default:
|
||||
OSReport("%08x\n", consoleType);
|
||||
break;
|
||||
}
|
||||
|
||||
__OSGetIOSRev(&ios);
|
||||
OSReport("Firmware : %d.%d.%d ", ios.major, ios.minor, ios.micro);
|
||||
OSReport("(%d/%d/%d)\n", ios.month, ios.date, ios.year);
|
||||
sysMemSize = (OSGetConsoleSimulatedMem1Size() + OSGetConsoleSimulatedMem2Size());
|
||||
OSReport("Memory %d MB\n", sysMemSize/(1024*1024));
|
||||
|
||||
OSReport("MEM1 Arena : 0x%x - 0x%x\n", OSGetMEM1ArenaLo(), OSGetMEM1ArenaHi());
|
||||
OSReport("MEM2 Arena : 0x%x - 0x%x\n", OSGetMEM2ArenaLo(), OSGetMEM2ArenaHi());
|
||||
}
|
||||
|
||||
void OSInit(void) {
|
||||
void* bi2StartAddr;
|
||||
void* var_r31;
|
||||
void* arenaAddr = (void*)OSRoundUp32B(__ArenaLo);
|
||||
u32 sp10 = 0x81730000;
|
||||
|
||||
if (AreWeInitialized == FALSE) {
|
||||
AreWeInitialized = TRUE;
|
||||
|
||||
__OSStartTime = __OSGetSystemTime();
|
||||
OSDisableInterrupts();
|
||||
|
||||
__OSGetExecParams(&__OSRebootParams);
|
||||
PPCMtmmcr0(0);
|
||||
PPCMtmmcr1(0);
|
||||
PPCMtpmc1(0);
|
||||
PPCMtpmc2(0);
|
||||
PPCMtpmc3(0);
|
||||
PPCMtpmc4(0);
|
||||
PPCMthid4(0x83900000);
|
||||
PPCDisableSpeculation();
|
||||
PPCSetFpNonIEEEMode();
|
||||
|
||||
BootInfo = (OSBootInfo*)OSPhysicalToCached(0);
|
||||
BI2DebugFlag = 0;
|
||||
__DVDLongFileNameFlag = 0;
|
||||
|
||||
bi2StartAddr = (void*)(*(u32*)OSPhysicalToCached(0xF4));
|
||||
if (bi2StartAddr) {
|
||||
BI2DebugFlag = (void*)((char*)bi2StartAddr + 0xC);
|
||||
__PADSpec = ((u32*)bi2StartAddr)[9];
|
||||
*(u8*)OSPhysicalToCached(0x30E8) = *BI2DebugFlag;
|
||||
*(u8*)OSPhysicalToCached(0x30E9) = __PADSpec;
|
||||
} else if (BootInfo->arenaHi) {
|
||||
BI2DebugFlagHolder = *(u8*)OSPhysicalToCached(0x30E8);
|
||||
BI2DebugFlag = &BI2DebugFlagHolder;
|
||||
__PADSpec = *(u8*)OSPhysicalToCached(0x30E9);
|
||||
}
|
||||
|
||||
__DVDLongFileNameFlag = 1;
|
||||
|
||||
var_r31 = (void*)*(u32*)OSPhysicalToCached(0x310C);
|
||||
if (var_r31 == NULL) {
|
||||
if (OSIsMEM1Region(arenaAddr)) {
|
||||
var_r31 = !BootInfo->arenaLo ? arenaAddr : BootInfo->arenaLo;
|
||||
|
||||
if (!BootInfo->arenaLo && (BI2DebugFlag && (*(BI2DebugFlag) < 2))) {
|
||||
var_r31 = (void*)OSRoundUp32B(_stack_addr);
|
||||
}
|
||||
} else {
|
||||
var_r31 = (void*)0x80004000;
|
||||
}
|
||||
}
|
||||
|
||||
OSSetMEM1ArenaLo(var_r31);
|
||||
|
||||
var_r31 = (void*)*(u32*)OSPhysicalToCached(0x3110);
|
||||
if (var_r31 == NULL) {
|
||||
var_r31 = !BootInfo->arenaHi ? (void*)sp10 : BootInfo->arenaHi;
|
||||
}
|
||||
|
||||
OSSetMEM1ArenaHi(var_r31);
|
||||
|
||||
var_r31 = (void*)*(u32*)OSPhysicalToCached(0x3124);
|
||||
if (var_r31 != 0) {
|
||||
if (OSIsMEM2Region(arenaAddr)) {
|
||||
var_r31 = arenaAddr;
|
||||
|
||||
if ((BI2DebugFlag && (*(BI2DebugFlag) < 2))) {
|
||||
var_r31 = (void*)OSRoundUp32B(_stack_addr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((u32)var_r31 >= 0x90000000 && (u32)var_r31 < 0x90000800) {
|
||||
var_r31 = (void*)0x90000800;
|
||||
}
|
||||
}
|
||||
|
||||
OSSetMEM2ArenaLo(var_r31);
|
||||
}
|
||||
|
||||
|
||||
var_r31 = (void*)*(u32*)OSPhysicalToCached(0x3128);
|
||||
if (var_r31 != 0) {
|
||||
OSSetMEM2ArenaHi(var_r31);
|
||||
}
|
||||
|
||||
__OSInitIPCBuffer();
|
||||
OSExceptionInit();
|
||||
__OSInitSystemCall();
|
||||
__OSInitAlarm();
|
||||
__OSModuleInit();
|
||||
__OSInterruptInit();
|
||||
__OSContextInit();
|
||||
__OSCacheInit();
|
||||
EXIInit();
|
||||
SIInit();
|
||||
__OSInitSram();
|
||||
__OSThreadInit();
|
||||
__OSInitAudioSystem();
|
||||
|
||||
DisableWriteGatherPipe();
|
||||
|
||||
if (!__OSInIPL) {
|
||||
__OSInitMemoryProtection();
|
||||
}
|
||||
|
||||
ReportOSInfo();
|
||||
OSRegisterVersion(__OSVersion);
|
||||
|
||||
// if location of debug flag exists, and flag is >= 2, enable MetroTRKInterrupts
|
||||
if (BI2DebugFlag && ((*BI2DebugFlag) >= 2)) {
|
||||
EnableMetroTRKInterrupts();
|
||||
}
|
||||
|
||||
if (!__OSInNandBoot && !__OSInReboot) {
|
||||
ClearArena();
|
||||
ClearMEM2Arena();
|
||||
}
|
||||
|
||||
OSEnableInterrupts();
|
||||
IPCCltInit();
|
||||
|
||||
if (!__OSInNandBoot && !__OSInReboot) {
|
||||
__OSInitSTM();
|
||||
|
||||
SCInit();
|
||||
|
||||
/* do nothing until SC is not busy */
|
||||
while (SCCheckStatus() == 1) {}
|
||||
|
||||
__OSInitNet();
|
||||
}
|
||||
|
||||
if (!__OSInIPL) {
|
||||
CheckTargets();
|
||||
#ifdef SDK_AUG2010
|
||||
CheckFirmare();
|
||||
#endif
|
||||
DVDInit();
|
||||
|
||||
if (__OSIsGcam) {
|
||||
__OSDeviceCode = 0x9000;
|
||||
} else if (!__OSDeviceCode) {
|
||||
DCInvalidateRange(&DriveInfo, sizeof(DriveInfo));
|
||||
DVDInquiryAsync(&DriveBlock, &DriveInfo, InquiryCallback);
|
||||
}
|
||||
|
||||
if (OSGetAppType() == 0x80 && !__OSInReboot) {
|
||||
if (!__DVDCheckDevice()) {
|
||||
OSReturnToMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!__OSInIPL && !__OSInNandBoot) {
|
||||
__OSInitPlayTime();
|
||||
}
|
||||
|
||||
if (!__OSInIPL && !__OSInNandBoot && !__OSInReboot) {
|
||||
__OSStartPlayRecord();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u32 __OSExceptionLocations[] = {
|
||||
0x00000100, 0x00000200, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000800,
|
||||
0x00000900, 0x00000C00, 0x00000D00, 0x00000F00, 0x00001300, 0x00001400, 0x00001700,
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
char * __OSExceptionNames[17] = {
|
||||
"System reset",
|
||||
"MachineCheck",
|
||||
"DSI",
|
||||
"ISI",
|
||||
"External Int.",
|
||||
"Alignment",
|
||||
"Program",
|
||||
"FP Unavailable",
|
||||
"Decrementer",
|
||||
"System call",
|
||||
"Trace",
|
||||
"Perf mon",
|
||||
"IABR",
|
||||
"SMI",
|
||||
"Thermal Int.",
|
||||
"Protection error",
|
||||
"FP Exception",
|
||||
};
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
ASSERTMSGLINE(1830, ((u32)&__OSEVEnd - (u32)&__OSEVStart) <= 0x100, "OSExceptionInit(): too big exception vector code.");
|
||||
|
||||
// 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
|
||||
{
|
||||
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 < __OS_EXCEPTION_MAX; exception++) {
|
||||
if (BI2DebugFlag && (*BI2DebugFlag >= 2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Modify the copy of code in text before transferring
|
||||
// to the exception table.
|
||||
*opCodeAddr = oldOpCode | exception;
|
||||
|
||||
// Modify opcodes at __DBVECTOR if necessary
|
||||
// make sure the opcodes are still nop
|
||||
{
|
||||
u32* ops = (u32*)__DBVECTOR;
|
||||
int cb;
|
||||
|
||||
for (cb = 0; cb < (u32)__OSDBJUMPEND - (u32)__OSDBJUMPSTART; cb += sizeof(u32)) {
|
||||
*ops++ = NOP;
|
||||
}
|
||||
}
|
||||
|
||||
// Install the modified handler.
|
||||
destAddr = (void*)OSPhysicalToCached(__OSExceptionLocations[(u32)exception]);
|
||||
memcpy(destAddr, handlerStart, handlerSize);
|
||||
DCFlushRangeNoSync(destAddr, handlerSize);
|
||||
__sync();
|
||||
ICInvalidateRange(destAddr, handlerSize);
|
||||
}
|
||||
// initialize pointer to exception table
|
||||
OSExceptionTable = (void*)OSPhysicalToCached(OS_EXCEPTIONTABLE_ADDR);
|
||||
|
||||
// install default exception handlers
|
||||
for (exception = 0; exception < __OS_EXCEPTION_MAX; exception++) {
|
||||
__OSSetExceptionHandler(exception, OSDefaultExceptionHandler);
|
||||
}
|
||||
|
||||
// restore the old opcode, so that we can re-start an application without
|
||||
// downloading the text segments
|
||||
*opCodeAddr = oldOpCode;
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void __OSDBIntegrator(void) {
|
||||
nofralloc
|
||||
entry __OSDBINTSTART
|
||||
li r5, OS_DBINTERFACE_ADDR
|
||||
mflr r3
|
||||
stw r3, DB_EXCEPTIONRET_OFFSET(r5)
|
||||
lwz r3, DB_EXCEPTIONDEST_OFFSET(r5)
|
||||
oris r3, r3, OS_CACHED_REGION_PREFIX
|
||||
mtlr r3
|
||||
li r3, 0x30 // MSR_IR | MSR_DR // turn on memory addressing
|
||||
mtmsr r3
|
||||
blr
|
||||
entry __OSDBINTEND
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void __OSDBJump(void) {
|
||||
nofralloc
|
||||
entry __OSDBJUMPSTART
|
||||
bla OS_DBJUMPPOINT_ADDR
|
||||
entry __OSDBJUMPEND
|
||||
}
|
||||
#endif
|
||||
|
||||
__OSExceptionHandler __OSSetExceptionHandler(__OSException exception, __OSExceptionHandler handler) {
|
||||
__OSExceptionHandler oldHandler;
|
||||
|
||||
ASSERTMSGLINE(1974, exception < __OS_EXCEPTION_MAX, "__OSSetExceptionHandler(): unknown exception.");
|
||||
|
||||
oldHandler = OSExceptionTable[exception];
|
||||
OSExceptionTable[exception] = handler;
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
__OSExceptionHandler __OSGetExceptionHandler(__OSException exception) {
|
||||
ASSERTMSGLINE(1997, exception < __OS_EXCEPTION_MAX, "__OSGetExceptionHandler(): unknown exception.");
|
||||
return OSExceptionTable[exception];
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void OSExceptionVector(void) {
|
||||
nofralloc
|
||||
|
||||
entry __OSEVStart
|
||||
// Save r4 into SPRG0
|
||||
mtsprg 0, r4
|
||||
|
||||
// Load current context physical address into r4
|
||||
lwz r4, OS_CURRENTCONTEXT_PADDR
|
||||
|
||||
// Save r3 - r5 into the current context
|
||||
stw r3, OS_CONTEXT_R3(r4)
|
||||
mfsprg r3, 0
|
||||
stw r3, OS_CONTEXT_R4(r4)
|
||||
stw r5, OS_CONTEXT_R5(r4)
|
||||
|
||||
lhz r3, OS_CONTEXT_STATE(r4)
|
||||
ori r3, r3, OS_CONTEXT_STATE_EXC
|
||||
sth r3, OS_CONTEXT_STATE(r4)
|
||||
|
||||
// Save misc registers
|
||||
mfcr r3
|
||||
stw r3, OS_CONTEXT_CR(r4)
|
||||
mflr r3
|
||||
stw r3, OS_CONTEXT_LR(r4)
|
||||
mfctr r3
|
||||
stw r3, OS_CONTEXT_CTR(r4)
|
||||
mfxer r3
|
||||
stw r3, OS_CONTEXT_XER(r4)
|
||||
mfsrr0 r3
|
||||
stw r3, OS_CONTEXT_SRR0(r4)
|
||||
mfsrr1 r3
|
||||
stw r3, OS_CONTEXT_SRR1(r4)
|
||||
mr r5, r3
|
||||
|
||||
entry __DBVECTOR
|
||||
nop
|
||||
|
||||
// Set SRR1[IR|DR] to turn on address
|
||||
// translation at the next RFI
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
// This lets us change the exception number based on the
|
||||
// exception we're installing.
|
||||
entry __OSEVSetNumber
|
||||
addi r3, 0, 0x0000
|
||||
|
||||
// Load current context virtual address into r4
|
||||
lwz r4, 0xD4
|
||||
|
||||
// Check non-recoverable interrupt
|
||||
rlwinm. r5, r5, 0, MSR_RI_BIT, MSR_RI_BIT
|
||||
bne recoverable
|
||||
addis r5, 0, OSDefaultExceptionHandler@ha
|
||||
addi r5, r5, OSDefaultExceptionHandler@l
|
||||
mtsrr0 r5
|
||||
rfi
|
||||
// NOT REACHED HERE
|
||||
|
||||
recoverable:
|
||||
// Locate exception handler.
|
||||
rlwinm r5, r3, 2, 22, 29 // r5 contains exception*4
|
||||
lwz r5, OS_EXCEPTIONTABLE_ADDR(r5)
|
||||
mtsrr0 r5
|
||||
|
||||
// Final state
|
||||
// r3 - exception number
|
||||
// r4 - pointer to context
|
||||
// r5 - garbage
|
||||
// srr0 - exception handler
|
||||
// srr1 - address translation enalbed, not yet recoverable
|
||||
|
||||
rfi
|
||||
// NOT REACHED HERE
|
||||
// The handler will restore state
|
||||
|
||||
entry __OSEVEnd
|
||||
nop
|
||||
}
|
||||
#endif
|
||||
|
||||
void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar);
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm void OSDefaultExceptionHandler(register __OSException exception, register OSContext* context) {
|
||||
nofralloc
|
||||
OS_EXCEPTION_SAVE_GPRS(context)
|
||||
mfdsisr r5
|
||||
mfdar r6
|
||||
|
||||
stwu r1, -8(r1)
|
||||
b __OSUnhandledException
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
void __OSPSInit(void) {
|
||||
PPCMthid2(PPCMfhid2() | 0x80000000 | 0x20000000);
|
||||
ICFlashInvalidate();
|
||||
__sync();
|
||||
|
||||
asm
|
||||
{
|
||||
li r3, 0
|
||||
mtspr GQR0, r3
|
||||
mtspr GQR1, r3
|
||||
mtspr GQR2, r3
|
||||
mtspr GQR3, r3
|
||||
mtspr GQR4, r3
|
||||
mtspr GQR5, r3
|
||||
mtspr GQR6, r3
|
||||
mtspr GQR7, r3
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 __OSGetDIConfig(void) {
|
||||
return (__DIRegs[9] & 0xFF);
|
||||
}
|
||||
|
||||
void OSRegisterVersion(const char* id) {
|
||||
OSReport("%s\n", id);
|
||||
}
|
||||
|
||||
#if SDK_SEP2006
|
||||
static const char* AppGameNameForSysMenu = "HAEA";
|
||||
|
||||
const char* OSGetAppGamename(void) {
|
||||
const char* appNameSrc = (char*)OSPhysicalToCached(0x3180);
|
||||
|
||||
if (__OSInIPL) {
|
||||
appNameSrc = AppGameNameForSysMenu;
|
||||
}
|
||||
|
||||
GameNameBuffer[0] = *appNameSrc++;
|
||||
GameNameBuffer[1] = *appNameSrc++;
|
||||
GameNameBuffer[2] = *appNameSrc++;
|
||||
GameNameBuffer[3] = *appNameSrc;
|
||||
GameNameBuffer[4] = 0x00;
|
||||
return GameNameBuffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
u8 OSGetAppType(void) {
|
||||
if (__OSInIPL) {
|
||||
return 0x40;
|
||||
}
|
||||
|
||||
return *((u8*)OSPhysicalToCached(0x3184)) & 0xFF;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#include <revolution/os.h>
|
||||
|
||||
// undefine the macros so they do not error the file.
|
||||
#undef OSPhysicalToCached
|
||||
#undef OSPhysicalToUncached
|
||||
#undef OSCachedToPhysical
|
||||
#undef OSUncachedToPhysical
|
||||
#undef OSCachedToUncached
|
||||
#undef OSUncachedToCached
|
||||
|
||||
void* OSPhysicalToCached(u32 paddr) {
|
||||
ASSERTMSGLINE(56, paddr < 0x20000000U, "OSPhysicalToCached(): illegal address.");
|
||||
return (void*)(paddr + 0x80000000);
|
||||
}
|
||||
|
||||
void* OSPhysicalToUncached(u32 paddr) {
|
||||
ASSERTMSGLINE(71, paddr < 0x20000000U, "OSPhysicalToUncached(): illegal address.");
|
||||
return (void*)(paddr - 0x40000000);
|
||||
}
|
||||
|
||||
u32 OSCachedToPhysical(void* caddr) {
|
||||
ASSERTMSGLINE(86, 0x80000000U <= (u32)caddr && (u32)caddr < 0xA0000000U, "OSCachedToPhysical(): illegal address.");
|
||||
return (u32)caddr + 0x80000000;
|
||||
}
|
||||
|
||||
u32 OSUncachedToPhysical(void* ucaddr) {
|
||||
ASSERTMSGLINE(101, 0xC0000000U <= (u32)ucaddr && (u32)ucaddr < 0xE0000000U, "OSUncachedToPhysical(): illegal address.");
|
||||
return (u32)ucaddr + 0x40000000;
|
||||
}
|
||||
|
||||
void* OSCachedToUncached(void* caddr) {
|
||||
ASSERTMSGLINE(116, 0x80000000U <= (u32)caddr && (u32)caddr < 0xA0000000U, "OSCachedToUncached(): illegal address.");
|
||||
return (void*)((u32)caddr + 0x40000000);
|
||||
}
|
||||
|
|
@ -0,0 +1,324 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
#include "__dvd.h"
|
||||
|
||||
typedef struct {
|
||||
OSAlarm* head;
|
||||
OSAlarm* tail;
|
||||
} OSAlarmQueue;
|
||||
|
||||
// prototypes
|
||||
static void SetTimer(OSAlarm * alarm);
|
||||
static void InsertAlarm(OSAlarm* alarm, OSTime fire, OSAlarmHandler handler);
|
||||
static void DecrementerExceptionCallback(register __OSException exception, register OSContext* context);
|
||||
static void DecrementerExceptionHandler(__OSException exception, OSContext* context);
|
||||
static BOOL OnReset(BOOL final, u32 event);
|
||||
|
||||
static OSShutdownFunctionInfo ResetFunctionInfo = {OnReset, 0xFFFFFFFF, NULL, NULL};
|
||||
static OSAlarmQueue AlarmQueue;
|
||||
|
||||
#define ASSERTREPORT(line, cond) \
|
||||
if (!(cond)) { OSReport("OSCheckAlarmQueue: Failed " #cond " in %d", line); return 0; }
|
||||
|
||||
BOOL OSCheckAlarmQueue(void) {
|
||||
OSAlarm* alarm;
|
||||
|
||||
ASSERTREPORT(181, AlarmQueue.head == NULL && AlarmQueue.tail == NULL || AlarmQueue.head != NULL && AlarmQueue.tail != NULL);
|
||||
ASSERTREPORT(182, AlarmQueue.head == NULL || AlarmQueue.head->prev == NULL);
|
||||
ASSERTREPORT(183, AlarmQueue.tail == NULL || AlarmQueue.tail->next == NULL);
|
||||
|
||||
for (alarm = AlarmQueue.head; alarm; alarm = alarm->next) {
|
||||
ASSERTREPORT(186, alarm->next == NULL || alarm->next->prev == alarm);
|
||||
ASSERTREPORT(187, alarm->next != NULL || AlarmQueue.tail == alarm);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void SetTimer(OSAlarm* alarm) {
|
||||
OSTime delta = alarm->fire - __OSGetSystemTime();
|
||||
|
||||
if (delta < 0) {
|
||||
PPCMtdec(0);
|
||||
} else if (delta < 0x80000000) {
|
||||
PPCMtdec((u32)delta);
|
||||
} else {
|
||||
PPCMtdec(0x7fffffff);
|
||||
}
|
||||
}
|
||||
|
||||
void __OSInitAlarm(void) {
|
||||
if (__OSGetExceptionHandler(8) != DecrementerExceptionHandler) {
|
||||
AlarmQueue.head = AlarmQueue.tail = NULL;
|
||||
__OSSetExceptionHandler(8, DecrementerExceptionHandler);
|
||||
OSRegisterShutdownFunction(&ResetFunctionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void OSCreateAlarm(OSAlarm* alarm) {
|
||||
alarm->handler = 0;
|
||||
alarm->tag = 0;
|
||||
}
|
||||
|
||||
static void InsertAlarm(OSAlarm* alarm, OSTime fire, OSAlarmHandler handler) {
|
||||
OSAlarm* next;
|
||||
OSAlarm* prev;
|
||||
|
||||
if (0 < alarm->period) {
|
||||
OSTime time = __OSGetSystemTime();
|
||||
|
||||
fire = alarm->start;
|
||||
if (alarm->start < time) {
|
||||
fire += alarm->period * ((time - alarm->start) / alarm->period + 1);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERTLINE(290, alarm->handler == 0);
|
||||
|
||||
alarm->handler = handler;
|
||||
alarm->fire = fire;
|
||||
|
||||
for (next = AlarmQueue.head; next; next = next->next) {
|
||||
if (next->fire <= fire) {
|
||||
continue;
|
||||
}
|
||||
|
||||
alarm->prev = next->prev;
|
||||
next->prev = alarm;
|
||||
alarm->next = next;
|
||||
prev = alarm->prev;
|
||||
|
||||
if (prev) {
|
||||
prev->next = alarm;
|
||||
} else {
|
||||
AlarmQueue.head = alarm;
|
||||
SetTimer(alarm);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERTLINE(319, next == 0);
|
||||
|
||||
alarm->next = 0;
|
||||
prev = AlarmQueue.tail;
|
||||
AlarmQueue.tail = alarm;
|
||||
alarm->prev = prev;
|
||||
|
||||
if (prev) {
|
||||
prev->next = alarm;
|
||||
} else {
|
||||
AlarmQueue.head = AlarmQueue.tail = alarm;
|
||||
SetTimer(alarm);
|
||||
}
|
||||
}
|
||||
|
||||
void OSSetAlarm(OSAlarm* alarm, OSTime tick, OSAlarmHandler handler) {
|
||||
BOOL enabled;
|
||||
ASSERTMSGLINE(352, tick > 0, "OSSetAlarm(): tick was less than zero.");
|
||||
ASSERTMSGLINE(353, handler, "OSSetAlarm(): null handler was specified.");
|
||||
enabled = OSDisableInterrupts();
|
||||
alarm->period = 0;
|
||||
InsertAlarm(alarm, __OSGetSystemTime() + tick, handler);
|
||||
ASSERTLINE(360, OSCheckAlarmQueue());
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSSetAbsAlarm(OSAlarm* alarm, OSTime time, OSAlarmHandler handler) {
|
||||
BOOL enabled;
|
||||
|
||||
ASSERTMSGLINE(343, handler, "OSSetAbsAlarm(): null handler was specified.");
|
||||
enabled = OSDisableInterrupts();
|
||||
alarm->period = 0;
|
||||
InsertAlarm(alarm, __OSTimeToSystemTime(time), handler);
|
||||
ASSERTLINE(350, OSCheckAlarmQueue());
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSSetPeriodicAlarm(OSAlarm* alarm, OSTime start, OSTime period, OSAlarmHandler handler) {
|
||||
BOOL enabled;
|
||||
ASSERTMSGLINE(413, period > 0, "OSSetPeriodicAlarm(): period was less than zero.");
|
||||
ASSERTMSGLINE(414, handler, "OSSetPeriodicAlarm(): null handler was specified.");
|
||||
enabled = OSDisableInterrupts();
|
||||
alarm->period = period;
|
||||
alarm->start = __OSTimeToSystemTime(start);
|
||||
InsertAlarm(alarm, 0, handler);
|
||||
ASSERTLINE(422, OSCheckAlarmQueue());
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSCancelAlarm(OSAlarm* alarm) {
|
||||
OSAlarm* next;
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
if (alarm->handler == 0) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return;
|
||||
}
|
||||
|
||||
next = alarm->next;
|
||||
if (next == 0) {
|
||||
AlarmQueue.tail = alarm->prev;
|
||||
} else {
|
||||
next->prev = alarm->prev;
|
||||
}
|
||||
if (alarm->prev) {
|
||||
alarm->prev->next = next;
|
||||
} else {
|
||||
AlarmQueue.head = next;
|
||||
if (next) {
|
||||
SetTimer(next);
|
||||
}
|
||||
}
|
||||
alarm->handler = 0;
|
||||
ASSERTLINE(473, OSCheckAlarmQueue());
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
static void DecrementerExceptionCallback(register __OSException exception,
|
||||
register OSContext* context) {
|
||||
OSAlarm* alarm;
|
||||
OSAlarm* next;
|
||||
OSAlarmHandler handler;
|
||||
OSTime time;
|
||||
OSContext exceptionContext;
|
||||
|
||||
time = __OSGetSystemTime();
|
||||
alarm = AlarmQueue.head;
|
||||
if (alarm == 0) {
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
if (time < alarm->fire) {
|
||||
SetTimer(alarm);
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
next = alarm->next;
|
||||
AlarmQueue.head = next;
|
||||
if (next == 0) {
|
||||
AlarmQueue.tail = 0;
|
||||
} else {
|
||||
next->prev = 0;
|
||||
}
|
||||
|
||||
ASSERTLINE(531, OSCheckAlarmQueue());
|
||||
|
||||
handler = alarm->handler;
|
||||
alarm->handler = 0;
|
||||
if (0 < alarm->period) {
|
||||
InsertAlarm(alarm, 0, handler);
|
||||
ASSERTLINE(541, OSCheckAlarmQueue());
|
||||
}
|
||||
|
||||
if (AlarmQueue.head) {
|
||||
SetTimer(AlarmQueue.head);
|
||||
}
|
||||
|
||||
OSDisableScheduler();
|
||||
OSClearContext(&exceptionContext);
|
||||
OSSetCurrentContext(&exceptionContext);
|
||||
handler(alarm, context);
|
||||
OSClearContext(&exceptionContext);
|
||||
OSSetCurrentContext(context);
|
||||
OSEnableScheduler();
|
||||
__OSReschedule();
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void DecrementerExceptionHandler(register __OSException exception,
|
||||
register OSContext* context) {
|
||||
nofralloc
|
||||
OS_EXCEPTION_SAVE_GPRS(context)
|
||||
stwu r1, -8(r1)
|
||||
b DecrementerExceptionCallback
|
||||
}
|
||||
#endif
|
||||
|
||||
void OSSetAlarmTag(OSAlarm* alarm, u32 tag) {
|
||||
alarm->tag = tag;
|
||||
}
|
||||
|
||||
void OSCancelAlarms(u32 tag) {
|
||||
BOOL enabled;
|
||||
OSAlarm* alarm;
|
||||
OSAlarm* next;
|
||||
|
||||
ASSERTMSGLINE(569, tag != 0, "OSCancelAlarms(): invalid tag. (this tag is used by the operating system.)");
|
||||
|
||||
if (tag != 0) {
|
||||
enabled = OSDisableInterrupts();
|
||||
ASSERTLINE(575, OSCheckAlarmQueue());
|
||||
|
||||
alarm = AlarmQueue.head;
|
||||
next = (alarm) ? alarm->next : NULL;
|
||||
|
||||
while (alarm != 0) {
|
||||
if (alarm->tag == tag) {
|
||||
OSCancelAlarm(alarm);
|
||||
}
|
||||
|
||||
alarm = next;
|
||||
next = (alarm) ? alarm->next : NULL;
|
||||
}
|
||||
|
||||
ASSERTLINE(585, OSCheckAlarmQueue());
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL OnReset(BOOL final, u32 event) {
|
||||
OSAlarm* alarm;
|
||||
OSAlarm* next;
|
||||
|
||||
if (final != FALSE) {
|
||||
ASSERTLINE(656, OSCheckAlarmQueue());
|
||||
|
||||
for (alarm = AlarmQueue.head, next = alarm ? alarm->next : 0; alarm; alarm = next, next = alarm ? alarm->next : 0) {
|
||||
if (!__DVDTestAlarm(alarm)) {
|
||||
OSCancelAlarm(alarm);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERTLINE(668, OSCheckAlarmQueue());
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void __OSCancelInternalAlarms(void* userdata) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSAlarm* alarm;
|
||||
OSAlarm* next;
|
||||
|
||||
ASSERTLINE(723, OSCheckAlarmQueue());
|
||||
|
||||
for (alarm = AlarmQueue.head, next = alarm ? alarm->next : 0; alarm; alarm = next, next = alarm ? alarm->next : 0) {
|
||||
if (alarm->tag == -1 && alarm->userData == userdata) {
|
||||
OSCancelAlarm(alarm);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERTLINE(737, OSCheckAlarmQueue());
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
// NOTE: these functions don't exist in tp debug, OSReports are made up to create string data
|
||||
void OSSetAlarmUserData(OSAlarm* alarm, void* userData) {
|
||||
#if DEBUG
|
||||
OSReport("OSSetAlarmUserData");
|
||||
OSReport("NULL pointer is detected at %s");
|
||||
#endif
|
||||
alarm->userData = userData;
|
||||
}
|
||||
|
||||
void* OSGetAlarmUserData(const OSAlarm* alarm) {
|
||||
#if DEBUG
|
||||
OSReport("OSGetAlarmUserData");
|
||||
#endif
|
||||
return alarm->userData;
|
||||
}
|
||||
|
|
@ -0,0 +1,608 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#define ALIGNMENT 32
|
||||
|
||||
#define InRange(cell, arenaStart, arenaEnd) \
|
||||
((u32) arenaStart <= (u32) cell) && ((u32) cell < (u32) arenaEnd)
|
||||
|
||||
#define HEADERSIZE 32u
|
||||
#define MINOBJSIZE 64u
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ENABLE_HEAPDESC
|
||||
#endif
|
||||
|
||||
typedef struct Cell Cell;
|
||||
typedef struct HeapDesc HeapDesc;
|
||||
struct Cell {
|
||||
Cell* prev;
|
||||
Cell* next;
|
||||
s32 size;
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
HeapDesc* hd;
|
||||
s32 requested;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct HeapDesc {
|
||||
s32 size;
|
||||
Cell* free;
|
||||
Cell* allocated;
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
u32 paddingBytes;
|
||||
u32 headerBytes;
|
||||
u32 payloadBytes;
|
||||
#endif
|
||||
};
|
||||
|
||||
volatile int __OSCurrHeap = -1;
|
||||
|
||||
static HeapDesc* HeapArray;
|
||||
static int NumHeaps;
|
||||
static void* ArenaStart;
|
||||
static void* ArenaEnd;
|
||||
|
||||
// prototypes
|
||||
static Cell* DLAddFront(Cell* list, Cell* cell);
|
||||
static Cell* DLLookup(Cell* list, Cell* cell);
|
||||
static Cell* DLExtract(Cell* list, Cell* cell);
|
||||
static Cell* DLInsert(Cell* list, Cell* cell);
|
||||
static int DLOverlap(Cell* list, void* start, void* end);
|
||||
static s32 DLSize(Cell* list);
|
||||
|
||||
static Cell* DLAddFront(Cell* list, Cell* cell) {
|
||||
cell->next = list;
|
||||
cell->prev = 0;
|
||||
if (list) {
|
||||
list->prev = cell;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
static Cell* DLLookup(Cell* list, Cell* cell) {
|
||||
for(; list; list = list->next) {
|
||||
if (list == cell) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Cell* DLExtract(Cell* list, Cell* cell) {
|
||||
if (cell->next) {
|
||||
cell->next->prev = cell->prev;
|
||||
}
|
||||
if (cell->prev == NULL) {
|
||||
return cell->next;
|
||||
}
|
||||
cell->prev->next = cell->next;
|
||||
return list;
|
||||
}
|
||||
|
||||
static Cell* DLInsert(Cell* list, Cell* cell) {
|
||||
Cell* prev;
|
||||
Cell* next;
|
||||
|
||||
for(next = list, prev = NULL; next != 0; prev = next, next = next->next) {
|
||||
if (cell <= next) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cell->next = next;
|
||||
cell->prev = prev;
|
||||
if (next) {
|
||||
next->prev = cell;
|
||||
if ((u8*)cell + cell->size == (u8*)next) {
|
||||
cell->size += next->size;
|
||||
next = next->next;
|
||||
cell->next = next;
|
||||
if (next) {
|
||||
next->prev = cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prev) {
|
||||
prev->next = cell;
|
||||
if ((u8*)prev + prev->size == (u8*)cell) {
|
||||
prev->size += cell->size;
|
||||
prev->next = next;
|
||||
if (next) {
|
||||
next->prev = prev;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
static int DLOverlap(Cell* list, void* start, void* end) {
|
||||
Cell* cell = list;
|
||||
|
||||
while(cell) {
|
||||
if (((start <= cell)
|
||||
&& (cell < end))
|
||||
|| ((start < (void* ) ((u8*)cell + cell->size))
|
||||
&& ((void* ) ((u8*)cell + cell->size) <= end))) {
|
||||
return 1;
|
||||
}
|
||||
cell = cell->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 DLSize(Cell* list) {
|
||||
Cell* cell;
|
||||
s32 size;
|
||||
|
||||
size = 0;
|
||||
cell = list;
|
||||
|
||||
while(cell) {
|
||||
size += cell->size;
|
||||
cell = cell->next;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void* OSAllocFromHeap(int heap, u32 size) {
|
||||
HeapDesc* hd;
|
||||
Cell* cell;
|
||||
Cell* newCell;
|
||||
s32 leftoverSize;
|
||||
s32 requested;
|
||||
|
||||
requested = size;
|
||||
ASSERTMSGLINE(337, HeapArray, "OSAllocFromHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(338, (s32)size > 0, "OSAllocFromHeap(): invalid size.");
|
||||
ASSERTMSGLINE(339, heap >= 0 && heap < NumHeaps, "OSAllocFromHeap(): invalid heap handle.");
|
||||
ASSERTMSGLINE(340, HeapArray[heap].size >= 0, "OSAllocFromHeap(): invalid heap handle.");
|
||||
|
||||
hd = &HeapArray[heap];
|
||||
size += 0x20;
|
||||
size = (size + 0x1F) & 0xFFFFFFE0;
|
||||
|
||||
for(cell = hd->free; cell != NULL; cell = cell->next) {
|
||||
if ((signed)size <= (signed)cell->size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cell == NULL) {
|
||||
#if DEBUG
|
||||
OSReport("OSAllocFromHeap: Warning- failed to allocate %d bytes\n", size);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
ASSERTMSGLINE(364, !((s32)cell & 0x1F), "OSAllocFromHeap(): heap is broken.");
|
||||
ASSERTMSGLINE(365, cell->hd == NULL, "OSAllocFromHeap(): heap is broken.");
|
||||
|
||||
leftoverSize = cell->size - size;
|
||||
if (leftoverSize < 0x40U) {
|
||||
hd->free = DLExtract(hd->free, cell);
|
||||
} else {
|
||||
cell->size = size;
|
||||
newCell = (void*)((u8*)cell + size);
|
||||
newCell->size = leftoverSize;
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
newCell->hd = 0;
|
||||
#endif
|
||||
newCell->prev = cell->prev;
|
||||
newCell->next = cell->next;
|
||||
if (newCell->next != NULL) {
|
||||
newCell->next->prev = newCell;
|
||||
}
|
||||
if (newCell->prev != NULL) {
|
||||
newCell->prev->next = newCell;
|
||||
} else {
|
||||
ASSERTMSGLINE(394, hd->free == cell, "OSAllocFromHeap(): heap is broken.");
|
||||
hd->free = newCell;
|
||||
}
|
||||
}
|
||||
|
||||
hd->allocated = DLAddFront(hd->allocated, cell);
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
cell->hd = hd;
|
||||
cell->requested = requested;
|
||||
hd->headerBytes += 0x20;
|
||||
hd->paddingBytes += (cell->size - (requested + 0x20));
|
||||
hd->payloadBytes += requested;
|
||||
#endif
|
||||
return (u8*)cell + 0x20;
|
||||
}
|
||||
|
||||
void* OSAllocFixed(void* rstart, void* rend) {
|
||||
int i;
|
||||
Cell* cell;
|
||||
Cell* newCell;
|
||||
HeapDesc* hd;
|
||||
void* start;
|
||||
void* end;
|
||||
void* cellEnd;
|
||||
|
||||
start = (void*)((*(u32*)rstart) & ~((32)-1));
|
||||
end = (void*)((*(u32*)rend + 0x1FU) & ~((32)-1));
|
||||
|
||||
ASSERTMSGLINE(436, HeapArray, "OSAllocFixed(): heap is not initialized.");
|
||||
ASSERTMSGLINE(437, (u32)start < (u32)end, "OSAllocFixed(): invalid range.");
|
||||
ASSERTMSGLINE(439, ((u32) ArenaStart <= (u32) start) && ((u32) end <= (u32) ArenaEnd), "OSAllocFixed(): invalid range.");
|
||||
|
||||
for(i = 0; i < NumHeaps; i++) {
|
||||
hd = &HeapArray[i];
|
||||
if(hd->size >= 0) {
|
||||
if (DLOverlap(hd->allocated, start, end)) {
|
||||
#if DEBUG
|
||||
OSReport("OSAllocFixed: Warning - failed to allocate from %p to %p\n", start, end);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < NumHeaps; i++) {
|
||||
hd = &HeapArray[i];
|
||||
if (hd->size >= 0) {
|
||||
for(cell = hd->free; cell; cell = cell->next) {
|
||||
cellEnd = ((u8*)cell + cell->size);
|
||||
if(cellEnd > start) {
|
||||
if (end <= cell) {
|
||||
break;
|
||||
}
|
||||
if ((char*)start-0x20 <= (char*)cell && cell < end && (start <= cellEnd) && (cellEnd < ((char*)end + 0x40))) {
|
||||
if (cell < start) {
|
||||
start = cell;
|
||||
}
|
||||
if (end < cellEnd) {
|
||||
end = cellEnd;
|
||||
}
|
||||
hd->free = DLExtract(hd->free, cell);
|
||||
hd->size -= cell->size;
|
||||
} else if((char*)start-0x20 <= (char*)cell && cell < end) {
|
||||
if (cell < start) {
|
||||
start = cell;
|
||||
}
|
||||
ASSERTLINE(503, MINOBJSIZE <= (char*) cellEnd - (char*) end);
|
||||
newCell = (Cell*)end;
|
||||
|
||||
newCell->size = (s32) ((char*)cellEnd - (char*)end);
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
newCell->hd = 0;
|
||||
#endif
|
||||
newCell->next = cell->next;
|
||||
if (newCell->next) {
|
||||
newCell->next->prev = newCell;
|
||||
}
|
||||
newCell->prev = cell->prev;
|
||||
if (newCell->prev) {
|
||||
newCell->prev->next = newCell;
|
||||
} else {
|
||||
hd->free = newCell;
|
||||
}
|
||||
hd->size -= ((char*)end - (char*)cell);
|
||||
break;
|
||||
} else {
|
||||
if ((start <= cellEnd) && (cellEnd < ((char*)end + 0x40U))) {
|
||||
if (end < cellEnd) {
|
||||
end = cellEnd;
|
||||
}
|
||||
ASSERTLINE(528, MINOBJSIZE <= (char*) start - (char*) cell);
|
||||
hd->size -= ((char*)cellEnd - (char*)start);
|
||||
cell->size = ((char*)start - (char*)cell);
|
||||
} else {
|
||||
ASSERTLINE(535, MINOBJSIZE <= (char*) cellEnd - (char*) end);
|
||||
newCell = (Cell*)end;
|
||||
newCell->size = ((char*)cellEnd - (char*)end);
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
newCell->hd = 0;
|
||||
#endif
|
||||
newCell->next = cell->next;
|
||||
if (newCell->next) {
|
||||
newCell->next->prev = newCell;
|
||||
}
|
||||
newCell->prev = cell;
|
||||
cell->next = newCell;
|
||||
cell->size = ((char*)start - (char*)cell);
|
||||
hd->size -= ((char*)end - (char*)start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERTLINE(550, 0 <= hd->size);
|
||||
}
|
||||
}
|
||||
ASSERTLINE(553, OFFSET(start, ALIGNMENT) == 0);
|
||||
ASSERTLINE(554, OFFSET(end, ALIGNMENT) == 0);
|
||||
ASSERTLINE(555, start < end);
|
||||
*(u32*)rstart = (u32)start;
|
||||
*(u32*)rend = (u32)end;
|
||||
return (void*)*(u32*)rstart;
|
||||
}
|
||||
|
||||
void OSFreeToHeap(int heap, void* ptr) {
|
||||
HeapDesc* hd;
|
||||
Cell* cell;
|
||||
|
||||
ASSERTMSGLINE(589, HeapArray, "OSFreeToHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(591, ((u32)ArenaStart+0x20) <= (u32)ptr && (u32)ptr < (u32)ArenaEnd, "OSFreeToHeap(): invalid pointer.");
|
||||
ASSERTMSGLINE(592, OFFSET(ptr, ALIGNMENT) == 0, "OSFreeToHeap(): invalid pointer.");
|
||||
ASSERTMSGLINE(593, HeapArray[heap].size >= 0, "OSFreeToHeap(): invalid heap handle.");
|
||||
cell = (void*)((u32)ptr-0x20);
|
||||
hd = &HeapArray[heap];
|
||||
ASSERTMSGLINE(598, cell->hd == hd, "OSFreeToHeap(): invalid pointer.");
|
||||
ASSERTMSGLINE(599, DLLookup(hd->allocated, cell), "OSFreeToHeap(): invalid pointer.");
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
cell->hd = 0;
|
||||
hd->headerBytes -= 0x20;
|
||||
hd->paddingBytes -= (cell->size - (cell->requested + 0x20));
|
||||
hd->payloadBytes -= cell->requested;
|
||||
#endif
|
||||
hd->allocated = DLExtract(hd->allocated, cell);
|
||||
hd->free = DLInsert(hd->free, cell);
|
||||
}
|
||||
|
||||
int OSSetCurrentHeap(int heap) {
|
||||
int prev;
|
||||
|
||||
ASSERTMSGLINE(631, HeapArray, "OSSetCurrentHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(632, (heap >= 0) && (heap < NumHeaps), "OSSetCurrentHeap(): invalid heap handle.");
|
||||
ASSERTMSGLINE(633, HeapArray[heap].size >= 0, "OSSetCurrentHeap(): invalid heap handle.");
|
||||
prev = __OSCurrHeap;
|
||||
__OSCurrHeap = heap;
|
||||
return prev;
|
||||
}
|
||||
|
||||
void* OSInitAlloc(void* arenaStart, void* arenaEnd, int maxHeaps) {
|
||||
u32 arraySize;
|
||||
int i;
|
||||
|
||||
ASSERTMSGLINE(659, maxHeaps > 0, "OSInitAlloc(): invalid number of heaps.");
|
||||
ASSERTMSGLINE(661, (u32)arenaStart < (u32)arenaEnd, "OSInitAlloc(): invalid range.");
|
||||
ASSERTMSGLINE(664, maxHeaps <= (((u32)arenaEnd - (u32)arenaStart) / 24U), "OSInitAlloc(): too small range.");
|
||||
arraySize = maxHeaps * sizeof(HeapDesc);
|
||||
HeapArray = arenaStart;
|
||||
NumHeaps = maxHeaps;
|
||||
|
||||
for (i = 0; i < NumHeaps; i++) {
|
||||
HeapDesc* hd = &HeapArray[i];
|
||||
hd->size = -1;
|
||||
hd->free = hd->allocated = 0;
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0;
|
||||
#endif
|
||||
}
|
||||
__OSCurrHeap = -1;
|
||||
arenaStart = (void*) ((u32)((char*)HeapArray + arraySize));
|
||||
arenaStart = (void*) (((u32)arenaStart + 0x1F) & 0xFFFFFFE0);
|
||||
ArenaStart = arenaStart;
|
||||
ArenaEnd = (void*) ((u32)arenaEnd & 0xFFFFFFE0);
|
||||
ASSERTMSGLINE(692, ((u32)ArenaEnd - (u32)ArenaStart) >= 0x40U, "OSInitAlloc(): too small range.");
|
||||
return arenaStart;
|
||||
}
|
||||
|
||||
int OSCreateHeap(void* start, void* end) {
|
||||
int heap;
|
||||
HeapDesc* hd;
|
||||
Cell* cell;
|
||||
|
||||
ASSERTMSGLINE(717, HeapArray, "OSCreateHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(718, (u32)start < (u32)end, "OSCreateHeap(): invalid range.");
|
||||
|
||||
start = (void*)(((u32)start + 0x1FU) & ~((32)-1));
|
||||
end = (void*)(((u32)end) & ~((32)-1));
|
||||
|
||||
ASSERTMSGLINE(721, (u32)start < (u32)end, "OSCreateHeap(): invalid range.");
|
||||
ASSERTMSGLINE(723, (u32)ArenaStart <= (u32)start && (u32)end <= (u32)ArenaEnd, "OSCreateHeap(): invalid range.");
|
||||
ASSERTMSGLINE(725, ((u32)end - (u32)start) >= 0x40U, "OSCreateHeap(): too small range.");
|
||||
|
||||
#if DEBUG
|
||||
for(heap = 0; heap < NumHeaps; heap++) {
|
||||
if (HeapArray[heap].size >= 0) {
|
||||
ASSERTMSGLINE(735, !DLOverlap(HeapArray[heap].free, start, end), "OSCreateHeap(): invalid range.");
|
||||
ASSERTMSGLINE(737, !DLOverlap(HeapArray[heap].allocated, start, end), "OSCreateHeap(): invalid range.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for(heap = 0; heap < NumHeaps; heap++) {
|
||||
hd = &HeapArray[heap];
|
||||
if (hd->size < 0) {
|
||||
hd->size = (u32)end - (u32)start;
|
||||
cell = start;
|
||||
cell->prev = 0;
|
||||
cell->next = 0;
|
||||
cell->size = hd->size;
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
cell->hd = 0;
|
||||
#endif
|
||||
hd->free = cell;
|
||||
hd->allocated = 0;
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0;
|
||||
#endif
|
||||
return heap;
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
OSReport("OSCreateHeap: Warning - Failed to find free heap descriptor.");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
void OSDestroyHeap(int heap) {
|
||||
HeapDesc* hd;
|
||||
s32 size;
|
||||
|
||||
ASSERTMSGLINE(782, HeapArray, "OSDestroyHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(783, (heap >= 0) && (heap < NumHeaps), "OSDestroyHeap(): invalid heap handle.");
|
||||
ASSERTMSGLINE(784, HeapArray[heap].size >= 0, "OSDestroyHeap(): invalid heap handle.");
|
||||
|
||||
hd = &HeapArray[heap];
|
||||
#if DEBUG
|
||||
size = DLSize(hd->free);
|
||||
|
||||
if (hd->size != size) {
|
||||
OSReport("OSDestroyHeap(%d): Warning - free list size %d, heap size %d\n", heap, size, hd->size);
|
||||
}
|
||||
#endif
|
||||
|
||||
hd->size = -1;
|
||||
hd->free = hd->allocated = 0;
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0;
|
||||
if (__OSCurrHeap == heap) {
|
||||
__OSCurrHeap = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OSAddToHeap(int heap, void* start, void* end) {
|
||||
HeapDesc* hd;
|
||||
Cell* cell;
|
||||
int i;
|
||||
|
||||
ASSERTMSGLINE(830, HeapArray, "OSAddToHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(831, (heap >= 0) && (heap < NumHeaps), "OSAddToHeap(): invalid heap handle.");
|
||||
ASSERTMSGLINE(832, HeapArray[heap].size >= 0, "OSAddToHeap(): invalid heap handle.");
|
||||
|
||||
hd = &HeapArray[heap];
|
||||
|
||||
ASSERTMSGLINE(836, (u32)start < (u32)end, "OSAddToHeap(): invalid range.");
|
||||
|
||||
start = (void*)(((u32)start + 0x1F) & ~((32)-1));
|
||||
end = (void*)(((u32)end) & ~((32)-1));
|
||||
|
||||
ASSERTMSGLINE(840, ((u32)end - (u32)start) >= 0x40U, "OSAddToHeap(): too small range.");
|
||||
ASSERTMSGLINE(842, (u32)ArenaStart <= (u32)start && (u32)end <= (u32)ArenaEnd, "OSAddToHeap(): invalid range.");
|
||||
|
||||
#if DEBUG
|
||||
for(i = 0; i < NumHeaps; i++) {
|
||||
if (HeapArray[i].size >= 0) {
|
||||
ASSERTMSGLINE(852, !DLOverlap(HeapArray[i].free, start, end), "OSAddToHeap(): invalid range.");
|
||||
ASSERTMSGLINE(854, !DLOverlap(HeapArray[i].allocated, start, end), "OSAddToHeap(): invalid range.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
cell = (Cell*)start;
|
||||
cell->size = ((char*)end - (char*)start);
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
cell->hd = 0;
|
||||
#endif
|
||||
hd->size += cell->size;
|
||||
hd->free = DLInsert(hd->free, cell);
|
||||
}
|
||||
|
||||
// custom macro for OSCheckHeap
|
||||
#define ASSERTREPORT(line, cond) \
|
||||
if (!(cond)) { OSReport("OSCheckHeap: Failed " #cond " in %d", line); return -1; }
|
||||
|
||||
s32 OSCheckHeap(int heap) {
|
||||
HeapDesc* hd;
|
||||
Cell* cell;
|
||||
s32 total = 0;
|
||||
s32 free = 0;
|
||||
|
||||
ASSERTREPORT(898, HeapArray);
|
||||
ASSERTREPORT(899, 0 <= heap && heap < NumHeaps);
|
||||
hd = &HeapArray[heap];
|
||||
ASSERTREPORT(902, 0 <= hd->size);
|
||||
|
||||
ASSERTREPORT(0x388, hd->allocated == NULL || hd->allocated->prev == NULL);
|
||||
|
||||
for(cell = hd->allocated; cell; cell = cell->next) {
|
||||
ASSERTREPORT(907, InRange(cell, ArenaStart, ArenaEnd));
|
||||
ASSERTREPORT(908, OFFSET(cell, ALIGNMENT) == 0);
|
||||
ASSERTREPORT(909, cell->next == NULL || cell->next->prev == cell);
|
||||
ASSERTREPORT(910, MINOBJSIZE <= cell->size);
|
||||
ASSERTREPORT(911, OFFSET(cell->size, ALIGNMENT) == 0);
|
||||
total += cell->size;
|
||||
ASSERTREPORT(914, 0 < total && total <= hd->size);
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
ASSERTREPORT(917, cell->hd == hd);
|
||||
ASSERTREPORT(918, HEADERSIZE + cell->requested <= cell->size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ASSERTREPORT(922, hd->free == NULL || hd->free->prev == NULL);
|
||||
|
||||
for(cell = hd->free; cell; cell = cell->next) {
|
||||
ASSERTREPORT(925, InRange(cell, ArenaStart, ArenaEnd));
|
||||
ASSERTREPORT(926, OFFSET(cell, ALIGNMENT) == 0);
|
||||
ASSERTREPORT(927, cell->next == NULL || cell->next->prev == cell);
|
||||
ASSERTREPORT(928, MINOBJSIZE <= cell->size);
|
||||
ASSERTREPORT(929, OFFSET(cell->size, ALIGNMENT) == 0);
|
||||
ASSERTREPORT(930, cell->next == NULL || (char*) cell + cell->size < (char*) cell->next);
|
||||
total += cell->size;
|
||||
free = (cell->size + free);
|
||||
free -= HEADERSIZE;
|
||||
ASSERTREPORT(934, 0 < total && total <= hd->size);
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
ASSERTREPORT(937, cell->hd == NULL);
|
||||
#endif
|
||||
}
|
||||
ASSERTREPORT(941, total == hd->size);
|
||||
return free;
|
||||
}
|
||||
|
||||
u32 OSReferentSize(void* ptr) {
|
||||
Cell* cell;
|
||||
|
||||
ASSERTMSGLINE(960, HeapArray, "OSReferentSize(): heap is not initialized.");
|
||||
ASSERTMSGLINE(962, InRange(ptr, ArenaStart+HEADERSIZE, ArenaEnd), "OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(963, !OFFSET(ptr, 32), "OSReferentSize(): invalid pointer.");
|
||||
cell = (void*)((u32)ptr-HEADERSIZE);
|
||||
ASSERTMSGLINE(967, cell->hd, "OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(969, !(((u32)cell->hd - (u32)HeapArray) % 24), "OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(971, ((u32)HeapArray <= (u32)cell->hd) && ((u32)cell->hd < (u32)((u32)HeapArray + (NumHeaps * 0x18))), "OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(972, cell->hd->size >= 0, "OSReferentSize(): invalid pointer.");
|
||||
ASSERTMSGLINE(974, DLLookup(cell->hd->allocated, cell), "OSReferentSize(): invalid pointer.");
|
||||
return (s32)((u32)cell->size-HEADERSIZE);
|
||||
}
|
||||
|
||||
void OSDumpHeap(int heap) {
|
||||
HeapDesc* hd;
|
||||
Cell* cell;
|
||||
|
||||
OSReport("\nOSDumpHeap(%d):\n", heap);
|
||||
ASSERTMSGLINE(995, HeapArray, "OSDumpHeap(): heap is not initialized.");
|
||||
ASSERTMSGLINE(996, (heap >= 0) && (heap < NumHeaps), "OSDumpHeap(): invalid heap handle.");
|
||||
hd = &HeapArray[heap];
|
||||
if (hd->size < 0) {
|
||||
OSReport("--------Inactive\n");
|
||||
return;
|
||||
}
|
||||
ASSERTMSGLINE(1005, OSCheckHeap(heap) >= 0, "OSDumpHeap(): heap is broken.");
|
||||
#ifdef ENABLE_HEAPDESC
|
||||
OSReport("padding %d/(%f%%) header %d/(%f%%) payload %d/(%f%%)\n",
|
||||
hd->paddingBytes, (100.0 * hd->paddingBytes / hd->size), hd->headerBytes, (100.0 * hd->headerBytes / hd->size), hd->payloadBytes,
|
||||
(100.0 * hd->payloadBytes / hd->size));
|
||||
#endif
|
||||
OSReport("addr size end prev next\n");
|
||||
OSReport("--------Allocated\n");
|
||||
|
||||
ASSERTMSGLINE(1018, hd->allocated == NULL || hd->allocated->prev == NULL, "OSDumpHeap(): heap is broken.");
|
||||
|
||||
for(cell = hd->allocated; cell; cell = cell->next) {
|
||||
OSReport("%x %d %x %x %x\n", cell, cell->size, (char*)cell + cell->size, cell->prev, cell->next);
|
||||
}
|
||||
OSReport("--------Free\n");
|
||||
for(cell = hd->free; cell; cell = cell->next) {
|
||||
OSReport("%x %d %x %x %x\n", cell, cell->size, (char*)cell + cell->size, cell->prev, cell->next);
|
||||
}
|
||||
}
|
||||
|
||||
void OSVisitAllocated(void (*visitor)(void*, u32)) {
|
||||
u32 heap;
|
||||
Cell* cell;
|
||||
|
||||
for(heap = 0; heap < NumHeaps; heap++) {
|
||||
if (HeapArray[heap].size >= 0) {
|
||||
for(cell = HeapArray[heap].allocated; cell; cell = cell->next) {
|
||||
visitor((char*)cell+HEADERSIZE, cell->size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1))
|
||||
#define TRUNC(n, a) (((u32)(n)) & ~((a)-1))
|
||||
|
||||
static void* s_mem2ArenaHi;
|
||||
static void* __OSArenaHi;
|
||||
|
||||
static void* __OSArenaLo = (void*)-1;
|
||||
static void* s_mem2ArenaLo = (void*)-1;
|
||||
|
||||
void* OSGetMEM1ArenaHi(void) {
|
||||
ASSERTMSGLINE(71, (u32)__OSArenaLo != -1, "OSGetArenaHi(): OSInit() must be called in advance.");
|
||||
ASSERTMSGLINE(73, (u32)__OSArenaLo <= (u32)__OSArenaHi, "OSGetArenaHi(): invalid arena (hi < lo).");
|
||||
return __OSArenaHi;
|
||||
}
|
||||
|
||||
void* OSGetMEM2ArenaHi(void) {
|
||||
return s_mem2ArenaHi;
|
||||
}
|
||||
|
||||
void* OSGetArenaHi(void) {
|
||||
return OSGetMEM1ArenaHi();
|
||||
}
|
||||
|
||||
void* OSGetMEM1ArenaLo(void) {
|
||||
ASSERTMSGLINE(99, (u32)__OSArenaLo != -1, "OSGetArenaLo(): OSInit() must be called in advance.");
|
||||
ASSERTMSGLINE(101, (u32)__OSArenaLo <= (u32)__OSArenaHi, "OSGetArenaLo(): invalid arena (hi < lo).");
|
||||
return __OSArenaLo;
|
||||
}
|
||||
|
||||
void* OSGetMEM2ArenaLo(void) {
|
||||
return s_mem2ArenaLo;
|
||||
}
|
||||
|
||||
void* OSGetArenaLo(void) {
|
||||
return OSGetMEM1ArenaLo();
|
||||
}
|
||||
|
||||
void OSSetMEM1ArenaHi(void* newHi) {
|
||||
__OSArenaHi = newHi;
|
||||
}
|
||||
|
||||
void OSSetMEM2ArenaHi(void* newHi) {
|
||||
s_mem2ArenaHi = newHi;
|
||||
}
|
||||
|
||||
void OSSetArenaHi(void* newHi) {
|
||||
OSSetMEM1ArenaHi(newHi);
|
||||
}
|
||||
|
||||
void OSSetMEM1ArenaLo(void* newLo) {
|
||||
__OSArenaLo = newLo;
|
||||
}
|
||||
|
||||
void OSSetMEM2ArenaLo(void* newLo) {
|
||||
s_mem2ArenaLo = newLo;
|
||||
}
|
||||
|
||||
void OSSetArenaLo(void* newLo) {
|
||||
OSSetMEM1ArenaLo(newLo);
|
||||
}
|
||||
|
||||
void* OSAllocFromMEM1ArenaLo(u32 size, u32 align) {
|
||||
void* ptr;
|
||||
u8* arenaLo;
|
||||
|
||||
ptr = OSGetMEM1ArenaLo();
|
||||
arenaLo = ptr = (void*)ROUND(ptr, align);
|
||||
arenaLo += size;
|
||||
arenaLo = (u8*)ROUND(arenaLo, align);
|
||||
OSSetMEM1ArenaLo(arenaLo);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* OSAllocFromMEM1ArenaHi(u32 size, u32 align) {
|
||||
void* ptr;
|
||||
u8* arenaHi;
|
||||
|
||||
arenaHi = OSGetMEM1ArenaHi();
|
||||
arenaHi = (u8*)TRUNC(arenaHi, align);
|
||||
arenaHi -= size;
|
||||
arenaHi = ptr = (void*)TRUNC(arenaHi, align);
|
||||
OSSetMEM1ArenaHi(arenaHi);
|
||||
return ptr;
|
||||
}
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
// prototypes
|
||||
void __AIClockInit(u32);
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
static void waitMicroSec(u32 usec) {
|
||||
OSTick start_tick = OSGetTick();
|
||||
while (OSTicksToMicroseconds(OSGetTick() - start_tick) < usec);
|
||||
}
|
||||
|
||||
#define PPCACR_OFFSET (OS_BASE_UNCACHED + 0x800000)
|
||||
#define PPCACR (0xD000000 + PPCACR_OFFSET)
|
||||
|
||||
#define busRd32(addr) (*(volatile u32 *)(addr))
|
||||
#define busWrt32(addr, val) (*(volatile u32 *)(addr)) = (val)
|
||||
|
||||
void __AIClockInit(u32 compatB) {
|
||||
u32 reg;
|
||||
|
||||
reg = busRd32(PPCACR + 0x180);
|
||||
reg &= ~((u32)1 << 8);
|
||||
reg |= ((u32)compatB << 8);
|
||||
reg &= ~((u32)1 << 7);
|
||||
busWrt32(PPCACR + 0x180, reg);
|
||||
|
||||
reg = busRd32(PPCACR + 0x1D0);
|
||||
reg &= ~((u32)1 << 31);
|
||||
reg &= ~((u32)1 << 30);
|
||||
busWrt32(PPCACR + 0x1D0, reg);
|
||||
|
||||
waitMicroSec(100);
|
||||
|
||||
if (compatB == 0) {
|
||||
reg = busRd32(PPCACR + 0x1CC);
|
||||
reg &= ~0x3FFC0;
|
||||
reg |= ((u32)63 << 6);
|
||||
reg &= ~0x3F;
|
||||
reg &= ~0x7FC0000;
|
||||
reg |= ((u32)281 << 18);
|
||||
busWrt32(PPCACR + 0x1CC, reg);
|
||||
} else {
|
||||
reg = busRd32(PPCACR + 0x1CC);
|
||||
reg &= ~0x3FFC0;
|
||||
reg |= ((u32)1023 << 6);
|
||||
reg &= ~0x3F;
|
||||
reg |= ((u32)14);
|
||||
reg &= ~0x7FC0000;
|
||||
reg |= ((u32)300 << 18);
|
||||
busWrt32(PPCACR + 0x1CC, reg);
|
||||
}
|
||||
|
||||
waitMicroSec(100);
|
||||
|
||||
reg = busRd32(PPCACR + 0x1D0);
|
||||
reg &= ~((u32)1 << 28);
|
||||
busWrt32(PPCACR + 0x1D0, reg);
|
||||
|
||||
waitMicroSec(1000);
|
||||
|
||||
reg = busRd32(PPCACR + 0x1D0);
|
||||
reg &= ~((u32)1 << 30);
|
||||
reg |= ((u32)1 << 30);
|
||||
busWrt32(PPCACR + 0x1D0, reg);
|
||||
|
||||
waitMicroSec(1000);
|
||||
|
||||
reg = busRd32(PPCACR + 0x1D0);
|
||||
reg &= ~((u32)1 << 31);
|
||||
reg |= ((u32)1 << 31);
|
||||
busWrt32(PPCACR + 0x1D0, reg);
|
||||
|
||||
waitMicroSec(1000);
|
||||
}
|
||||
|
||||
#define __DSPWorkBuffer (void*)0x81000000
|
||||
|
||||
void __OSInitAudioSystem(void) {
|
||||
u8 errFlag;
|
||||
u16 reg16;
|
||||
u32 start_tick;
|
||||
|
||||
if (!__OSInIPL) {
|
||||
__AIClockInit(1);
|
||||
}
|
||||
|
||||
memcpy((void*)((u32)OSGetArenaHi() - 0x80), __DSPWorkBuffer, sizeof(DSPInitCode));
|
||||
memcpy(__DSPWorkBuffer, (void*)DSPInitCode, sizeof(DSPInitCode));
|
||||
DCFlushRange(__DSPWorkBuffer, sizeof(DSPInitCode));
|
||||
|
||||
__DSPRegs[9] = 0x43;
|
||||
ASSERTMSGLINE(253, !(__DSPRegs[5] & 0x200), "__OSInitAudioSystem(): ARAM DMA already in progress");
|
||||
ASSERTMSGLINE(257, !(__DSPRegs[5] & 0x400), "__OSInitAudioSystem(): DSP DMA already in progress");
|
||||
ASSERTMSGLINE(261, (__DSPRegs[5] & 0x004), "__OSInitAudioSystem(): DSP already working");
|
||||
|
||||
__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;
|
||||
|
||||
reg16 = __DSPRegs[5];
|
||||
while (!(reg16 & 0x20))
|
||||
reg16 = __DSPRegs[5];
|
||||
|
||||
__DSPRegs[5] = reg16;
|
||||
|
||||
start_tick = OSGetTick();
|
||||
while ((s32)(OSGetTick() - start_tick) < 0x892);
|
||||
|
||||
*(u32*)&__DSPRegs[16] = 0x1000000;
|
||||
*(u32*)&__DSPRegs[18] = 0;
|
||||
*(u32*)&__DSPRegs[20] = 0x20;
|
||||
|
||||
reg16 = __DSPRegs[5];
|
||||
while (!(reg16 & 0x20)) {
|
||||
reg16 = __DSPRegs[5];
|
||||
}
|
||||
__DSPRegs[5] = reg16;
|
||||
|
||||
__DSPRegs[5] &= ~0x800;
|
||||
while ((__DSPRegs[5]) & 0x400);
|
||||
|
||||
__DSPRegs[5] &= ~4;
|
||||
errFlag = 0;
|
||||
|
||||
reg16 = __DSPRegs[2];
|
||||
|
||||
while (!(reg16 & 0x8000)) {
|
||||
reg16 = __DSPRegs[2];
|
||||
}
|
||||
|
||||
if(((u32)((reg16 << 16) | __DSPRegs[3]) + 0x7FAC0000U) != 0x4348) {
|
||||
ASSERTMSGLINE(333, 0, "__OSInitAudioSystem(): DSP returns invalid message");
|
||||
}
|
||||
|
||||
__DSPRegs[5] |= 4;
|
||||
__DSPRegs[5] = 0x8AC;
|
||||
__DSPRegs[5] |= 1;
|
||||
while (__DSPRegs[5] & 1);
|
||||
|
||||
memcpy(__DSPWorkBuffer, (void*)((u32)OSGetArenaHi() - 0x80), sizeof(DSPInitCode));
|
||||
}
|
||||
|
||||
void __OSStopAudioSystem(void) {
|
||||
u16 reg16;
|
||||
u32 start_tick;
|
||||
|
||||
#define waitUntil(load, mask) \
|
||||
reg16 = (load); \
|
||||
while (reg16 & (mask)) { \
|
||||
reg16 = (load); \
|
||||
}
|
||||
|
||||
__DSPRegs[5] = 0x804;
|
||||
reg16 = __DSPRegs[27];
|
||||
__DSPRegs[27] = reg16 & ~0x8000;
|
||||
waitUntil(__DSPRegs[5], 0x400);
|
||||
waitUntil(__DSPRegs[5], 0x200);
|
||||
__DSPRegs[5] = 0x8ac;
|
||||
__DSPRegs[0] = 0;
|
||||
|
||||
while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000);
|
||||
|
||||
start_tick = OSGetTick();
|
||||
while ((s32)(OSGetTick() - start_tick) < 0x2c);
|
||||
|
||||
reg16 = __DSPRegs[5];
|
||||
__DSPRegs[5] = reg16 | 1;
|
||||
waitUntil(__DSPRegs[5], 0x001);
|
||||
|
||||
#undef waitUntil
|
||||
}
|
||||
|
|
@ -0,0 +1,639 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/db.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
#define HID2 920
|
||||
|
||||
// prototypes
|
||||
void DMAErrorHandler(OSError error, OSContext* context, ...);
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm void DCFlashInvalidate(void) {
|
||||
nofralloc
|
||||
mfspr r3, HID0
|
||||
ori r3, r3, 0x400
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCEnable(void) {
|
||||
nofralloc
|
||||
sync
|
||||
mfspr r3, HID0
|
||||
ori r3, r3, 0x4000
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCDisable(void) {
|
||||
nofralloc
|
||||
sync
|
||||
mfspr r3, HID0
|
||||
rlwinm r3, r3, 0, 18, 16
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCFreeze(void) {
|
||||
nofralloc
|
||||
sync
|
||||
mfspr r3, HID0
|
||||
ori r3, r3, 0x1000
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCUnfreeze(void) {
|
||||
nofralloc
|
||||
mfspr r3, HID0
|
||||
rlwinm r3, r3, 0, 20, 18
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCTouchLoad(register void* addr) {
|
||||
nofralloc
|
||||
dcbt r0, addr
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCBlockZero(register void* addr) {
|
||||
nofralloc
|
||||
dcbz r0, addr
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCBlockStore(register void* addr) {
|
||||
nofralloc
|
||||
dcbst r0, addr
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCBlockFlush(register void* addr) {
|
||||
nofralloc
|
||||
dcbf r0, addr
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCBlockInvalidate(register void* addr) {
|
||||
nofralloc
|
||||
dcbi r0, addr
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCInvalidateRange(register void* addr, register u32 nBytes) {
|
||||
nofralloc
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
clrlwi r5, addr, 27
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 31
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
@1
|
||||
dcbi r0, addr
|
||||
addi addr, addr, 32
|
||||
bdnz @1
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCFlushRange(register void* addr, register u32 nBytes) {
|
||||
nofralloc
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
clrlwi r5, addr, 27
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 31
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
@1
|
||||
dcbf r0, addr
|
||||
addi addr, addr, 32
|
||||
bdnz @1
|
||||
sc
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCStoreRange(register void* addr, register u32 nBytes) {
|
||||
nofralloc
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
clrlwi r5, addr, 27
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 31
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
@1
|
||||
dcbst r0, addr
|
||||
addi addr, addr, 32
|
||||
bdnz @1
|
||||
sc
|
||||
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCFlushRangeNoSync(register void* addr, register u32 nBytes) {
|
||||
nofralloc
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
clrlwi r5, addr, 27
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 31
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
@1
|
||||
dcbf r0, addr
|
||||
addi addr, addr, 32
|
||||
bdnz @1
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCStoreRangeNoSync(register void* addr, register u32 nBytes) {
|
||||
nofralloc
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
clrlwi r5, addr, 27
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 31
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
@1
|
||||
dcbst r0, addr
|
||||
addi addr, addr, 32
|
||||
bdnz @1
|
||||
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCZeroRange(register void* addr, register u32 nBytes) {
|
||||
nofralloc
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
clrlwi r5, addr, 27
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 31
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
@1
|
||||
dcbz r0, addr
|
||||
addi addr, addr, 32
|
||||
bdnz @1
|
||||
|
||||
blr
|
||||
}
|
||||
|
||||
asm void DCTouchRange(register void* addr, register u32 nBytes) {
|
||||
nofralloc
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
clrlwi r5, addr, 27
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 31
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
@1
|
||||
dcbt r0, addr
|
||||
addi addr, addr, 32
|
||||
bdnz @1
|
||||
|
||||
blr
|
||||
}
|
||||
|
||||
asm void ICInvalidateRange(register void* addr, register u32 nBytes) {
|
||||
nofralloc
|
||||
cmplwi nBytes, 0
|
||||
blelr
|
||||
clrlwi r5, addr, 27
|
||||
add nBytes, nBytes, r5
|
||||
addi nBytes, nBytes, 31
|
||||
srwi nBytes, nBytes, 5
|
||||
mtctr nBytes
|
||||
|
||||
@1
|
||||
icbi r0, addr
|
||||
addi addr, addr, 32
|
||||
bdnz @1
|
||||
sync
|
||||
isync
|
||||
|
||||
blr
|
||||
}
|
||||
|
||||
asm void ICFlashInvalidate(void) {
|
||||
nofralloc
|
||||
mfspr r3, HID0
|
||||
ori r3, r3, 0x800
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void ICEnable(void) {
|
||||
nofralloc
|
||||
isync
|
||||
mfspr r3, HID0
|
||||
ori r3, r3, 0x8000
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void ICDisable(void) {
|
||||
nofralloc
|
||||
isync
|
||||
mfspr r3, HID0
|
||||
rlwinm r3, r3, 0, 17, 15
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void ICFreeze(void) {
|
||||
nofralloc
|
||||
isync
|
||||
mfspr r3, HID0
|
||||
ori r3, r3, 0x2000
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void ICUnfreeze(void) {
|
||||
nofralloc
|
||||
mfspr r3, HID0
|
||||
rlwinm r3, r3, 0, 19, 17
|
||||
mtspr HID0, r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm void ICBlockInvalidate(register void* addr) {
|
||||
nofralloc
|
||||
icbi r0, addr
|
||||
blr
|
||||
}
|
||||
|
||||
asm void ICSync(void) {
|
||||
nofralloc
|
||||
isync
|
||||
blr
|
||||
}
|
||||
|
||||
#define LC_LINES 512
|
||||
#define CACHE_LINES 1024
|
||||
|
||||
static asm void __LCEnable(void) {
|
||||
nofralloc
|
||||
mfmsr r5
|
||||
ori r5, r5, 0x1000
|
||||
mtmsr r5
|
||||
|
||||
lis r3, OS_CACHED_REGION_PREFIX
|
||||
li r4, CACHE_LINES
|
||||
mtctr r4
|
||||
_touchloop:
|
||||
dcbt 0,r3
|
||||
dcbst 0,r3
|
||||
addi r3,r3,32
|
||||
bdnz _touchloop
|
||||
mfspr r4, HID2
|
||||
oris r4, r4, 0x100F
|
||||
mtspr HID2, r4
|
||||
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
lis r3, LC_BASE_PREFIX
|
||||
ori r3, r3, 0x0002
|
||||
mtspr DBAT3L, r3
|
||||
ori r3, r3, 0x01fe
|
||||
mtspr DBAT3U, r3
|
||||
isync
|
||||
lis r3, LC_BASE_PREFIX
|
||||
li r6, LC_LINES
|
||||
mtctr r6
|
||||
li r6, 0
|
||||
|
||||
_lockloop:
|
||||
dcbz_l r6, r3
|
||||
addi r3, r3, 32
|
||||
bdnz+ _lockloop
|
||||
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
blr
|
||||
}
|
||||
|
||||
void LCEnable(void) {
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
__LCEnable();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
asm void LCDisable(void) {
|
||||
nofralloc
|
||||
lis r3, LC_BASE_PREFIX
|
||||
li r4, LC_LINES
|
||||
mtctr r4
|
||||
@1
|
||||
dcbi r0, r3
|
||||
addi r3, r3, 32
|
||||
bdnz @1
|
||||
mfspr r4, HID2
|
||||
rlwinm r4, r4, 0, 4, 2
|
||||
mtspr HID2, r4
|
||||
blr
|
||||
}
|
||||
|
||||
asm void LCAllocOneTag(register BOOL invalidate, register void* tag) {
|
||||
nofralloc
|
||||
cmpwi invalidate, 0
|
||||
beq @1
|
||||
dcbi r0, tag
|
||||
@1
|
||||
dcbz_l r0, tag
|
||||
blr
|
||||
}
|
||||
|
||||
asm void LCAllocTags(register BOOL invalidate, register void* startTag, register u32 numBlocks) {
|
||||
nofralloc
|
||||
mflr r6
|
||||
cmplwi numBlocks, 0
|
||||
ble @3
|
||||
mtctr numBlocks
|
||||
cmpwi invalidate, 0
|
||||
beq @2
|
||||
@1
|
||||
dcbi r0, startTag
|
||||
dcbz_l r0, startTag
|
||||
addi startTag, startTag, 32
|
||||
bdnz @1
|
||||
b @3
|
||||
@2
|
||||
dcbz_l r0, startTag
|
||||
addi startTag, startTag, 32
|
||||
bdnz @2
|
||||
@3
|
||||
mtlr r6
|
||||
blr
|
||||
}
|
||||
|
||||
asm void LCLoadBlocks(register void* destTag, register void* srcAddr, register u32 numBlocks) {
|
||||
nofralloc
|
||||
rlwinm r6, numBlocks, 30, 27, 31
|
||||
rlwinm srcAddr, srcAddr, 0, 4, 31
|
||||
or r6, r6, srcAddr
|
||||
mtspr DMA_U, r6
|
||||
rlwinm r6, numBlocks, 2, 28, 29
|
||||
or r6, r6, destTag
|
||||
ori r6, r6, 0x12
|
||||
mtspr DMA_L, r6
|
||||
blr
|
||||
}
|
||||
|
||||
asm void LCStoreBlocks(register void* destAddr, register void* srcTag, register u32 numBlocks) {
|
||||
nofralloc
|
||||
rlwinm r6, numBlocks, 30, 27, 31
|
||||
rlwinm destAddr, destAddr, 0, 3, 31
|
||||
or r6, r6, destAddr
|
||||
mtspr DMA_U, r6
|
||||
rlwinm r6, numBlocks, 2, 28, 29
|
||||
or r6, r6, srcTag
|
||||
ori r6, r6, 0x2
|
||||
mtspr DMA_L, r6
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
||||
void LCAlloc(void* addr, u32 nBytes) {
|
||||
u32 numBlocks = nBytes >> 5;
|
||||
u32 hid2 = PPCMfhid2();
|
||||
|
||||
ASSERTMSGLINE(1319, !((u32)addr & 31), "LCAlloc(): addr must be 32 byte aligned");
|
||||
ASSERTMSGLINE(1321, !((u32)nBytes & 31), "LCAlloc(): nBytes must be 32 byte aligned");
|
||||
|
||||
if ((hid2 & 0x10000000) == 0) {
|
||||
LCEnable();
|
||||
}
|
||||
LCAllocTags(TRUE, addr, numBlocks);
|
||||
}
|
||||
|
||||
void LCAllocNoInvalidate(void* addr, u32 nBytes) {
|
||||
u32 numBlocks = nBytes >> 5;
|
||||
u32 hid2 = PPCMfhid2();
|
||||
|
||||
ASSERTMSGLINE(1366, !((u32)addr & 31), "LCAllocNoFlush(): addr must be 32 byte aligned");
|
||||
ASSERTMSGLINE(1368, !((u32)nBytes & 31), "LCAllocNoFlush(): nBytes must be 32 byte aligned");
|
||||
|
||||
if ((hid2 & 0x10000000) == 0) {
|
||||
LCEnable();
|
||||
}
|
||||
LCAllocTags(FALSE, addr, numBlocks);
|
||||
}
|
||||
|
||||
u32 LCLoadData(void* destAddr, void* srcAddr, u32 nBytes) {
|
||||
u32 numBlocks = (nBytes + 31) / 32;
|
||||
u32 numTransactions = (numBlocks + 128 - 1) / 128;
|
||||
|
||||
ASSERTMSGLINE(1426, !((u32)srcAddr & 31), "LCLoadData(): srcAddr not 32 byte aligned");
|
||||
ASSERTMSGLINE(1428, !((u32)destAddr & 31), "LCLoadData(): destAddr not 32 byte aligned");
|
||||
|
||||
while (numBlocks > 0) {
|
||||
if (numBlocks < 128) {
|
||||
LCLoadBlocks(destAddr, srcAddr, numBlocks);
|
||||
numBlocks = 0;
|
||||
} else {
|
||||
LCLoadBlocks(destAddr, srcAddr, 0);
|
||||
numBlocks -= 128;
|
||||
destAddr = (void*)((u32)destAddr + 4096);
|
||||
srcAddr = (void*)((u32)srcAddr + 4096);
|
||||
}
|
||||
}
|
||||
|
||||
return numTransactions;
|
||||
}
|
||||
|
||||
u32 LCStoreData(void* destAddr, void* srcAddr, u32 nBytes) {
|
||||
u32 numBlocks = (nBytes + 31) / 32;
|
||||
u32 numTransactions = (numBlocks + 128 - 1) / 128;
|
||||
|
||||
ASSERTMSGLINE(1534, !((u32)srcAddr & 31), "LCStoreData(): srcAddr not 32 byte aligned");
|
||||
ASSERTMSGLINE(1536, !((u32)destAddr & 31), "LCStoreData(): destAddr not 32 byte aligned");
|
||||
|
||||
while (numBlocks > 0) {
|
||||
if (numBlocks < 128) {
|
||||
LCStoreBlocks(destAddr, srcAddr, numBlocks);
|
||||
numBlocks = 0;
|
||||
} else {
|
||||
LCStoreBlocks(destAddr, srcAddr, 0);
|
||||
numBlocks -= 128;
|
||||
destAddr = (void*)((u32)destAddr + 4096);
|
||||
srcAddr = (void*)((u32)srcAddr + 4096);
|
||||
}
|
||||
}
|
||||
|
||||
return numTransactions;
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm u32 LCQueueLength(void) {
|
||||
nofralloc
|
||||
mfspr r4, HID2
|
||||
rlwinm r3, r4, 8, 28, 31
|
||||
blr
|
||||
}
|
||||
|
||||
asm void LCQueueWait(register u32 len) {
|
||||
nofralloc
|
||||
@1
|
||||
mfspr r4, HID2
|
||||
rlwinm r4, r4, 8, 28, 31
|
||||
cmpw r4, r3
|
||||
bgt @1
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
||||
void LCFlushQueue() {
|
||||
union {
|
||||
u32 val;
|
||||
struct {
|
||||
u32 lcAddr : 27;
|
||||
u32 dmaLd : 1;
|
||||
u32 dmaLenL : 2;
|
||||
u32 dmaTrigger : 1;
|
||||
u32 dmaFlush : 1;
|
||||
} f;
|
||||
} dmaL;
|
||||
|
||||
dmaL.val = 0;
|
||||
dmaL.f.dmaFlush = 1;
|
||||
PPCMtdmaU(0);
|
||||
PPCMtdmaL(dmaL.val);
|
||||
PPCSync();
|
||||
}
|
||||
|
||||
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 L2Disable(void) {
|
||||
__sync();
|
||||
PPCMtl2cr(PPCMfl2cr() & ~0x80000000);
|
||||
__sync();
|
||||
}
|
||||
|
||||
void L2GlobalInvalidate(void) {
|
||||
L2Disable();
|
||||
PPCMtl2cr(PPCMfl2cr() | 0x00200000);
|
||||
while (PPCMfl2cr() & 0x00000001u);
|
||||
|
||||
PPCMtl2cr(PPCMfl2cr() & ~0x00200000);
|
||||
while (PPCMfl2cr() & 0x00000001u) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void L2SetDataOnly(BOOL dataOnly) {
|
||||
if (dataOnly) {
|
||||
PPCMtl2cr(PPCMfl2cr() | 0x400000);
|
||||
return;
|
||||
}
|
||||
PPCMtl2cr(PPCMfl2cr() & 0xFFBFFFFF);
|
||||
}
|
||||
|
||||
void L2SetWriteThrough(BOOL writeThrough) {
|
||||
if (writeThrough) {
|
||||
PPCMtl2cr(PPCMfl2cr() | 0x80000);
|
||||
return;
|
||||
}
|
||||
PPCMtl2cr(PPCMfl2cr() & 0xFFF7FFFF);
|
||||
}
|
||||
|
||||
void DMAErrorHandler(OSError error, OSContext* context, ...) {
|
||||
u32 hid2 = PPCMfhid2();
|
||||
|
||||
OSReport("Machine check received\n");
|
||||
OSReport("HID2 = 0x%x SRR1 = 0x%x\n", hid2, context->srr1);
|
||||
if (!(hid2 & (HID2_DCHERR | HID2_DNCERR | HID2_DCMERR | HID2_DQOERR)) || !(context->srr1 & SRR1_DMA_BIT)) {
|
||||
OSReport("Machine check was not DMA/locked cache related\n");
|
||||
OSDumpContext(context);
|
||||
PPCHalt();
|
||||
}
|
||||
|
||||
OSReport("DMAErrorHandler(): An error occurred while processing DMA.\n");
|
||||
OSReport("The following errors have been detected and cleared :\n");
|
||||
|
||||
if (hid2 & HID2_DCHERR) {
|
||||
OSReport("\t- Requested a locked cache tag that was already in the cache\n");
|
||||
}
|
||||
|
||||
if (hid2 & HID2_DNCERR) {
|
||||
OSReport("\t- DMA attempted to access normal cache\n");
|
||||
}
|
||||
|
||||
if (hid2 & HID2_DCMERR) {
|
||||
OSReport("\t- DMA missed in data cache\n");
|
||||
}
|
||||
|
||||
if (hid2 & HID2_DQOERR) {
|
||||
OSReport("\t- DMA queue overflowed\n");
|
||||
}
|
||||
|
||||
// write hid2 back to clear the error bits
|
||||
PPCMthid2(hid2);
|
||||
}
|
||||
|
||||
void __OSCacheInit() {
|
||||
if (!(PPCMfhid0() & HID0_ICE)) {
|
||||
ICEnable();
|
||||
}
|
||||
|
||||
if (!(PPCMfhid0() & HID0_DCE)) {
|
||||
DCEnable();
|
||||
}
|
||||
|
||||
if (!(PPCMfl2cr() & L2CR_L2E)) {
|
||||
L2Init();
|
||||
L2Enable();
|
||||
}
|
||||
|
||||
OSSetErrorHandler(OS_ERROR_MACHINE_CHECK, DMAErrorHandler);
|
||||
}
|
||||
|
|
@ -0,0 +1,653 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
// external functions
|
||||
extern void __RAS_OSDisableInterrupts_begin();
|
||||
extern void __RAS_OSDisableInterrupts_end();
|
||||
extern void DBPrintf(char*, ...);
|
||||
|
||||
#define HID2 920
|
||||
|
||||
volatile OSContext* __OSCurrentContext AT_ADDRESS(OS_BASE_CACHED | 0x00D4);
|
||||
volatile OSContext* __OSFPUContext AT_ADDRESS(OS_BASE_CACHED | 0x00D8);
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void __OSLoadFPUContext(register u32 dummy, register OSContext* fpucontext) {
|
||||
nofralloc
|
||||
lhz r5, fpucontext->state;
|
||||
clrlwi. r5, r5, 31
|
||||
beq _return
|
||||
|
||||
lfd fp0, OS_CONTEXT_FPSCR(fpucontext)
|
||||
mtfsf 0xFF, fp0
|
||||
mfspr r5, HID2
|
||||
rlwinm. r5, r5, 3, 31, 31
|
||||
beq _regular_FPRs
|
||||
|
||||
psq_l fp0, OS_CONTEXT_PSF0(fpucontext), 0, 0
|
||||
psq_l fp1, OS_CONTEXT_PSF1(fpucontext), 0, 0
|
||||
psq_l fp2, OS_CONTEXT_PSF2(fpucontext), 0, 0
|
||||
psq_l fp3, OS_CONTEXT_PSF3(fpucontext), 0, 0
|
||||
psq_l fp4, OS_CONTEXT_PSF4(fpucontext), 0, 0
|
||||
psq_l fp5, OS_CONTEXT_PSF5(fpucontext), 0, 0
|
||||
psq_l fp6, OS_CONTEXT_PSF6(fpucontext), 0, 0
|
||||
psq_l fp7, OS_CONTEXT_PSF7(fpucontext), 0, 0
|
||||
psq_l fp8, OS_CONTEXT_PSF8(fpucontext), 0, 0
|
||||
psq_l fp9, OS_CONTEXT_PSF9(fpucontext), 0, 0
|
||||
psq_l fp10, OS_CONTEXT_PSF10(fpucontext), 0, 0
|
||||
psq_l fp11, OS_CONTEXT_PSF11(fpucontext), 0, 0
|
||||
psq_l fp12, OS_CONTEXT_PSF12(fpucontext), 0, 0
|
||||
psq_l fp13, OS_CONTEXT_PSF13(fpucontext), 0, 0
|
||||
psq_l fp14, OS_CONTEXT_PSF14(fpucontext), 0, 0
|
||||
psq_l fp15, OS_CONTEXT_PSF15(fpucontext), 0, 0
|
||||
psq_l fp16, OS_CONTEXT_PSF16(fpucontext), 0, 0
|
||||
psq_l fp17, OS_CONTEXT_PSF17(fpucontext), 0, 0
|
||||
psq_l fp18, OS_CONTEXT_PSF18(fpucontext), 0, 0
|
||||
psq_l fp19, OS_CONTEXT_PSF19(fpucontext), 0, 0
|
||||
psq_l fp20, OS_CONTEXT_PSF20(fpucontext), 0, 0
|
||||
psq_l fp21, OS_CONTEXT_PSF21(fpucontext), 0, 0
|
||||
psq_l fp22, OS_CONTEXT_PSF22(fpucontext), 0, 0
|
||||
psq_l fp23, OS_CONTEXT_PSF23(fpucontext), 0, 0
|
||||
psq_l fp24, OS_CONTEXT_PSF24(fpucontext), 0, 0
|
||||
psq_l fp25, OS_CONTEXT_PSF25(fpucontext), 0, 0
|
||||
psq_l fp26, OS_CONTEXT_PSF26(fpucontext), 0, 0
|
||||
psq_l fp27, OS_CONTEXT_PSF27(fpucontext), 0, 0
|
||||
psq_l fp28, OS_CONTEXT_PSF28(fpucontext), 0, 0
|
||||
psq_l fp29, OS_CONTEXT_PSF29(fpucontext), 0, 0
|
||||
psq_l fp30, OS_CONTEXT_PSF30(fpucontext), 0, 0
|
||||
psq_l fp31, OS_CONTEXT_PSF31(fpucontext), 0, 0
|
||||
|
||||
_regular_FPRs:
|
||||
lfd fp0, fpucontext->fpr[0]
|
||||
lfd fp1, fpucontext->fpr[1]
|
||||
lfd fp2, fpucontext->fpr[2]
|
||||
lfd fp3, fpucontext->fpr[3]
|
||||
lfd fp4, fpucontext->fpr[4]
|
||||
lfd fp5, fpucontext->fpr[5]
|
||||
lfd fp6, fpucontext->fpr[6]
|
||||
lfd fp7, fpucontext->fpr[7]
|
||||
lfd fp8, fpucontext->fpr[8]
|
||||
lfd fp9, fpucontext->fpr[9]
|
||||
lfd fp10, fpucontext->fpr[10]
|
||||
lfd fp11, fpucontext->fpr[11]
|
||||
lfd fp12, fpucontext->fpr[12]
|
||||
lfd fp13, fpucontext->fpr[13]
|
||||
lfd fp14, fpucontext->fpr[14]
|
||||
lfd fp15, fpucontext->fpr[15]
|
||||
lfd fp16, fpucontext->fpr[16]
|
||||
lfd fp17, fpucontext->fpr[17]
|
||||
lfd fp18, fpucontext->fpr[18]
|
||||
lfd fp19, fpucontext->fpr[19]
|
||||
lfd fp20, fpucontext->fpr[20]
|
||||
lfd fp21, fpucontext->fpr[21]
|
||||
lfd fp22, fpucontext->fpr[22]
|
||||
lfd fp23, fpucontext->fpr[23]
|
||||
lfd fp24, fpucontext->fpr[24]
|
||||
lfd fp25, fpucontext->fpr[25]
|
||||
lfd fp26, fpucontext->fpr[26]
|
||||
lfd fp27, fpucontext->fpr[27]
|
||||
lfd fp28, fpucontext->fpr[28]
|
||||
lfd fp29, fpucontext->fpr[29]
|
||||
lfd fp30, fpucontext->fpr[30]
|
||||
lfd fp31, fpucontext->fpr[31]
|
||||
_return:
|
||||
blr
|
||||
}
|
||||
|
||||
static asm void __OSSaveFPUContext(register u32 dummy1, register u32 dummy2, register OSContext* fpucontext) {
|
||||
nofralloc
|
||||
|
||||
lhz r3, fpucontext->state
|
||||
ori r3, r3, 1
|
||||
sth r3, fpucontext->state
|
||||
|
||||
stfd fp0, fpucontext->fpr[0]
|
||||
stfd fp1, fpucontext->fpr[1]
|
||||
stfd fp2, fpucontext->fpr[2]
|
||||
stfd fp3, fpucontext->fpr[3]
|
||||
stfd fp4, fpucontext->fpr[4]
|
||||
stfd fp5, fpucontext->fpr[5]
|
||||
stfd fp6, fpucontext->fpr[6]
|
||||
stfd fp7, fpucontext->fpr[7]
|
||||
stfd fp8, fpucontext->fpr[8]
|
||||
stfd fp9, fpucontext->fpr[9]
|
||||
stfd fp10, fpucontext->fpr[10]
|
||||
stfd fp11, fpucontext->fpr[11]
|
||||
stfd fp12, fpucontext->fpr[12]
|
||||
stfd fp13, fpucontext->fpr[13]
|
||||
stfd fp14, fpucontext->fpr[14]
|
||||
stfd fp15, fpucontext->fpr[15]
|
||||
stfd fp16, fpucontext->fpr[16]
|
||||
stfd fp17, fpucontext->fpr[17]
|
||||
stfd fp18, fpucontext->fpr[18]
|
||||
stfd fp19, fpucontext->fpr[19]
|
||||
stfd fp20, fpucontext->fpr[20]
|
||||
stfd fp21, fpucontext->fpr[21]
|
||||
stfd fp22, fpucontext->fpr[22]
|
||||
stfd fp23, fpucontext->fpr[23]
|
||||
stfd fp24, fpucontext->fpr[24]
|
||||
stfd fp25, fpucontext->fpr[25]
|
||||
stfd fp26, fpucontext->fpr[26]
|
||||
stfd fp27, fpucontext->fpr[27]
|
||||
stfd fp28, fpucontext->fpr[28]
|
||||
stfd fp29, fpucontext->fpr[29]
|
||||
stfd fp30, fpucontext->fpr[30]
|
||||
stfd fp31, fpucontext->fpr[31]
|
||||
|
||||
mffs fp0
|
||||
stfd fp0, OS_CONTEXT_FPSCR(fpucontext)
|
||||
|
||||
lfd fp0, fpucontext->fpr[0]
|
||||
|
||||
mfspr r3, HID2
|
||||
rlwinm. r3, r3, 3, 31, 31
|
||||
bc 12, 2, _return
|
||||
|
||||
psq_st fp0, OS_CONTEXT_PSF0(fpucontext), 0, 0
|
||||
psq_st fp1, OS_CONTEXT_PSF1(fpucontext), 0, 0
|
||||
psq_st fp2, OS_CONTEXT_PSF2(fpucontext), 0, 0
|
||||
psq_st fp3, OS_CONTEXT_PSF3(fpucontext), 0, 0
|
||||
psq_st fp4, OS_CONTEXT_PSF4(fpucontext), 0, 0
|
||||
psq_st fp5, OS_CONTEXT_PSF5(fpucontext), 0, 0
|
||||
psq_st fp6, OS_CONTEXT_PSF6(fpucontext), 0, 0
|
||||
psq_st fp7, OS_CONTEXT_PSF7(fpucontext), 0, 0
|
||||
psq_st fp8, OS_CONTEXT_PSF8(fpucontext), 0, 0
|
||||
psq_st fp9, OS_CONTEXT_PSF9(fpucontext), 0, 0
|
||||
psq_st fp10, OS_CONTEXT_PSF10(fpucontext), 0, 0
|
||||
psq_st fp11, OS_CONTEXT_PSF11(fpucontext), 0, 0
|
||||
psq_st fp12, OS_CONTEXT_PSF12(fpucontext), 0, 0
|
||||
psq_st fp13, OS_CONTEXT_PSF13(fpucontext), 0, 0
|
||||
psq_st fp14, OS_CONTEXT_PSF14(fpucontext), 0, 0
|
||||
psq_st fp15, OS_CONTEXT_PSF15(fpucontext), 0, 0
|
||||
psq_st fp16, OS_CONTEXT_PSF16(fpucontext), 0, 0
|
||||
psq_st fp17, OS_CONTEXT_PSF17(fpucontext), 0, 0
|
||||
psq_st fp18, OS_CONTEXT_PSF18(fpucontext), 0, 0
|
||||
psq_st fp19, OS_CONTEXT_PSF19(fpucontext), 0, 0
|
||||
psq_st fp20, OS_CONTEXT_PSF20(fpucontext), 0, 0
|
||||
psq_st fp21, OS_CONTEXT_PSF21(fpucontext), 0, 0
|
||||
psq_st fp22, OS_CONTEXT_PSF22(fpucontext), 0, 0
|
||||
psq_st fp23, OS_CONTEXT_PSF23(fpucontext), 0, 0
|
||||
psq_st fp24, OS_CONTEXT_PSF24(fpucontext), 0, 0
|
||||
psq_st fp25, OS_CONTEXT_PSF25(fpucontext), 0, 0
|
||||
psq_st fp26, OS_CONTEXT_PSF26(fpucontext), 0, 0
|
||||
psq_st fp27, OS_CONTEXT_PSF27(fpucontext), 0, 0
|
||||
psq_st fp28, OS_CONTEXT_PSF28(fpucontext), 0, 0
|
||||
psq_st fp29, OS_CONTEXT_PSF29(fpucontext), 0, 0
|
||||
psq_st fp30, OS_CONTEXT_PSF30(fpucontext), 0, 0
|
||||
psq_st fp31, OS_CONTEXT_PSF31(fpucontext), 0, 0
|
||||
|
||||
_return:
|
||||
blr
|
||||
}
|
||||
|
||||
asm void OSLoadFPUContext(register OSContext* fpucontext) {
|
||||
nofralloc
|
||||
addi r4, fpucontext, 0
|
||||
b __OSLoadFPUContext
|
||||
}
|
||||
|
||||
asm void OSSaveFPUContext(register OSContext* fpucontext) {
|
||||
nofralloc
|
||||
addi r5, fpucontext, 0
|
||||
b __OSSaveFPUContext
|
||||
}
|
||||
|
||||
asm void OSSetCurrentContext(register OSContext* context){
|
||||
nofralloc
|
||||
|
||||
addis r4, r0, OS_CACHED_REGION_PREFIX
|
||||
|
||||
stw context, 0x00D4(r4)
|
||||
|
||||
clrlwi r5, context, 2
|
||||
stw r5, 0x00C0(r4)
|
||||
|
||||
lwz r5, 0x00D8(r4)
|
||||
cmpw r5, context
|
||||
bne _disableFPU
|
||||
|
||||
lwz r6, context->srr1
|
||||
ori r6, r6, 0x2000
|
||||
stw r6, context->srr1
|
||||
mfmsr r6
|
||||
ori r6, r6, 2
|
||||
mtmsr r6
|
||||
blr
|
||||
|
||||
_disableFPU:
|
||||
lwz r6, context->srr1
|
||||
rlwinm r6, r6, 0, 19, 17
|
||||
stw r6, context->srr1
|
||||
mfmsr r6
|
||||
rlwinm r6, r6, 0, 19, 17
|
||||
ori r6, r6, 2
|
||||
mtmsr r6
|
||||
isync
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
||||
OSContext* OSGetCurrentContext(void) {
|
||||
return (OSContext*)__OSCurrentContext;
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm u32 OSSaveContext(register OSContext* context) {
|
||||
nofralloc
|
||||
stmw r13, context->gpr[13]
|
||||
mfspr r0, GQR1
|
||||
stw r0, context->gqr[1]
|
||||
mfspr r0, GQR2
|
||||
stw r0, context->gqr[2]
|
||||
mfspr r0, GQR3
|
||||
stw r0, context->gqr[3]
|
||||
mfspr r0, GQR4
|
||||
stw r0, context->gqr[4]
|
||||
mfspr r0, GQR5
|
||||
stw r0, context->gqr[5]
|
||||
mfspr r0, GQR6
|
||||
stw r0, context->gqr[6]
|
||||
mfspr r0, GQR7
|
||||
stw r0, context->gqr[7]
|
||||
mfcr r0
|
||||
stw r0, context->cr
|
||||
mflr r0
|
||||
stw r0, context->lr
|
||||
stw r0, context->srr0
|
||||
mfmsr r0
|
||||
stw r0, context->srr1
|
||||
mfctr r0
|
||||
stw r0, context->ctr
|
||||
mfxer r0
|
||||
stw r0, context->xer
|
||||
stw r1, context->gpr[1]
|
||||
stw r2, context->gpr[2]
|
||||
li r0, 0x1
|
||||
stw r0, context->gpr[3]
|
||||
li r3, 0
|
||||
blr
|
||||
}
|
||||
|
||||
asm void OSLoadContext(register OSContext* context) {
|
||||
nofralloc
|
||||
|
||||
lis r4,__RAS_OSDisableInterrupts_begin@ha
|
||||
lwz r6,context->srr0
|
||||
addi r5,r4,__RAS_OSDisableInterrupts_begin@l
|
||||
cmplw r6,r5
|
||||
ble _notInRAS
|
||||
lis r4,__RAS_OSDisableInterrupts_end@ha
|
||||
addi r0,r4,__RAS_OSDisableInterrupts_end@l
|
||||
cmplw r6,r0
|
||||
bge _notInRAS
|
||||
stw r5,context->srr0
|
||||
|
||||
_notInRAS:
|
||||
|
||||
lwz r0, context->gpr[0]
|
||||
lwz r1, context->gpr[1]
|
||||
lwz r2, context->gpr[2]
|
||||
|
||||
lhz r4, context->state
|
||||
rlwinm. r5, r4, 0, 30, 30
|
||||
beq notexc
|
||||
rlwinm r4, r4, 0, 31, 29
|
||||
sth r4, context->state
|
||||
lmw r5, context->gpr[5]
|
||||
b misc
|
||||
notexc:
|
||||
lmw r13, context->gpr[13]
|
||||
misc:
|
||||
|
||||
lwz r4, context->gqr[1]
|
||||
mtspr GQR1, r4
|
||||
lwz r4, context->gqr[2]
|
||||
mtspr GQR2, r4
|
||||
lwz r4, context->gqr[3]
|
||||
mtspr GQR3, r4
|
||||
lwz r4, context->gqr[4]
|
||||
mtspr GQR4, r4
|
||||
lwz r4, context->gqr[5]
|
||||
mtspr GQR5, r4
|
||||
lwz r4, context->gqr[6]
|
||||
mtspr GQR6, r4
|
||||
lwz r4, context->gqr[7]
|
||||
mtspr GQR7, r4
|
||||
|
||||
lwz r4, context->cr
|
||||
mtcr r4
|
||||
lwz r4, context->lr
|
||||
mtlr r4
|
||||
lwz r4, context->ctr
|
||||
mtctr r4
|
||||
lwz r4, context->xer
|
||||
mtxer r4
|
||||
|
||||
mfmsr r4
|
||||
rlwinm r4, r4, 0, 17, 15
|
||||
rlwinm r4, r4, 0, 31, 29
|
||||
mtmsr r4
|
||||
|
||||
lwz r4, context->srr0
|
||||
mtsrr0 r4
|
||||
lwz r4, context->srr1
|
||||
mtsrr1 r4
|
||||
|
||||
lwz r4, context->gpr[4]
|
||||
lwz r3, context->gpr[3]
|
||||
|
||||
rfi
|
||||
}
|
||||
|
||||
asm u32 OSGetStackPointer() {
|
||||
nofralloc
|
||||
mr r3, r1
|
||||
blr
|
||||
}
|
||||
|
||||
asm u32 OSSwitchStack(register u32 newsp) {
|
||||
nofralloc
|
||||
mr r5, r1
|
||||
mr r1, newsp
|
||||
mr r3, r5
|
||||
blr
|
||||
}
|
||||
|
||||
asm int OSSwitchFiber(register u32 pc, register u32 newsp) {
|
||||
nofralloc
|
||||
mflr r0
|
||||
mr r5, r1
|
||||
stwu r5, -8(newsp)
|
||||
mr r1, newsp
|
||||
stw r0, 4(r5)
|
||||
mtlr pc
|
||||
blrl
|
||||
lwz r5, 0(r1)
|
||||
lwz r0, 4(r5)
|
||||
mtlr r0
|
||||
mr r1, r5
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm void OSSwitchFiberEx(register u32 param_0, register u32 param_1, register u32 param_2, register u32 param_3, register u32 pc, register u32 newsp) {
|
||||
nofralloc
|
||||
|
||||
mflr r0
|
||||
|
||||
// Back chain
|
||||
mr r9, r1
|
||||
stwu r9, -8(newsp)
|
||||
|
||||
// LR save
|
||||
mr r1, newsp
|
||||
stw r0, 4(r9)
|
||||
|
||||
// Call function
|
||||
mtlr pc
|
||||
blrl
|
||||
|
||||
// Switch back
|
||||
lwz r5, 0(r1)
|
||||
lwz r0, 4(r5)
|
||||
mtlr r0
|
||||
mr r1, r5
|
||||
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
||||
void OSClearContext(register OSContext* context) {
|
||||
context->mode = 0;
|
||||
context->state = 0;
|
||||
if (context == __OSFPUContext)
|
||||
__OSFPUContext = NULL;
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm void OSInitContext(register OSContext* context, register u32 pc, register u32 newsp) {
|
||||
nofralloc
|
||||
|
||||
stw pc, OS_CONTEXT_SRR0(context)
|
||||
stw newsp, OS_CONTEXT_R1(context)
|
||||
li r11, 0
|
||||
ori r11, r11, 0x00008000 | 0x00000020 | 0x00000010 | 0x00000002 | 0x00001000
|
||||
stw r11, OS_CONTEXT_SRR1(context)
|
||||
li r0, 0x0
|
||||
stw r0, OS_CONTEXT_CR(context)
|
||||
stw r0, OS_CONTEXT_XER(context)
|
||||
|
||||
|
||||
stw r2, OS_CONTEXT_R2(context)
|
||||
stw r13, OS_CONTEXT_R13(context)
|
||||
|
||||
stw r0, OS_CONTEXT_R3(context)
|
||||
stw r0, OS_CONTEXT_R4(context)
|
||||
stw r0, OS_CONTEXT_R5(context)
|
||||
stw r0, OS_CONTEXT_R6(context)
|
||||
stw r0, OS_CONTEXT_R7(context)
|
||||
stw r0, OS_CONTEXT_R8(context)
|
||||
stw r0, OS_CONTEXT_R9(context)
|
||||
stw r0, OS_CONTEXT_R10(context)
|
||||
stw r0, OS_CONTEXT_R11(context)
|
||||
stw r0, OS_CONTEXT_R12(context)
|
||||
|
||||
stw r0, OS_CONTEXT_R14(context)
|
||||
stw r0, OS_CONTEXT_R15(context)
|
||||
stw r0, OS_CONTEXT_R16(context)
|
||||
stw r0, OS_CONTEXT_R17(context)
|
||||
stw r0, OS_CONTEXT_R18(context)
|
||||
stw r0, OS_CONTEXT_R19(context)
|
||||
stw r0, OS_CONTEXT_R20(context)
|
||||
stw r0, OS_CONTEXT_R21(context)
|
||||
stw r0, OS_CONTEXT_R22(context)
|
||||
stw r0, OS_CONTEXT_R23(context)
|
||||
stw r0, OS_CONTEXT_R24(context)
|
||||
stw r0, OS_CONTEXT_R25(context)
|
||||
stw r0, OS_CONTEXT_R26(context)
|
||||
stw r0, OS_CONTEXT_R27(context)
|
||||
stw r0, OS_CONTEXT_R28(context)
|
||||
stw r0, OS_CONTEXT_R29(context)
|
||||
stw r0, OS_CONTEXT_R30(context)
|
||||
stw r0, OS_CONTEXT_R31(context)
|
||||
|
||||
stw r0, OS_CONTEXT_GQR0(context)
|
||||
stw r0, OS_CONTEXT_GQR1(context)
|
||||
stw r0, OS_CONTEXT_GQR2(context)
|
||||
stw r0, OS_CONTEXT_GQR3(context)
|
||||
stw r0, OS_CONTEXT_GQR4(context)
|
||||
stw r0, OS_CONTEXT_GQR5(context)
|
||||
stw r0, OS_CONTEXT_GQR6(context)
|
||||
stw r0, OS_CONTEXT_GQR7(context)
|
||||
|
||||
b OSClearContext
|
||||
}
|
||||
#endif
|
||||
|
||||
void OSDumpContext(OSContext* context) {
|
||||
u32 i;
|
||||
u32* p;
|
||||
|
||||
OSReport("------------------------- Context 0x%08x -------------------------\n", context);
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
OSReport("r%-2d = 0x%08x (%14d) r%-2d = 0x%08x (%14d)\n", i, context->gpr[i],
|
||||
context->gpr[i], i + 16, context->gpr[i + 16], context->gpr[i + 16]);
|
||||
}
|
||||
|
||||
OSReport("LR = 0x%08x CR = 0x%08x\n", context->lr, context->cr);
|
||||
OSReport("SRR0 = 0x%08x SRR1 = 0x%08x\n", context->srr0, context->srr1);
|
||||
|
||||
OSReport("\nGQRs----------\n");
|
||||
for (i = 0; i < 4; ++i) {
|
||||
OSReport("gqr%d = 0x%08x \t gqr%d = 0x%08x\n", i, context->gqr[i], i + 4, context->gqr[i + 4]);
|
||||
}
|
||||
|
||||
if (context->state & OS_CONTEXT_STATE_FPSAVED) {
|
||||
OSContext* currentContext;
|
||||
OSContext fpucontext;
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
currentContext = OSGetCurrentContext();
|
||||
OSClearContext(&fpucontext);
|
||||
OSSetCurrentContext(&fpucontext);
|
||||
|
||||
OSReport("\n\nFPRs----------\n");
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
OSReport("fr%d \t= %d \t fr%d \t= %d\n", i, (u32)context->fpr[i], i + 1,
|
||||
(u32)context->fpr[i + 1]);
|
||||
}
|
||||
OSReport("\n\nPSFs----------\n");
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
OSReport("ps%d \t= 0x%x \t ps%d \t= 0x%x\n", i, (u32)context->psf[i], i + 1,
|
||||
(u32)context->psf[i + 1]);
|
||||
}
|
||||
|
||||
OSClearContext(&fpucontext);
|
||||
OSSetCurrentContext(currentContext);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
OSReport("\nAddress: Back Chain LR Save\n");
|
||||
for (i = 0, p = (u32*)context->gpr[1]; p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) {
|
||||
OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void OSSwitchFPUContext(register __OSException exception, register OSContext* context) {
|
||||
nofralloc
|
||||
mfmsr r5
|
||||
ori r5, r5, 0x2000
|
||||
mtmsr r5
|
||||
isync
|
||||
lwz r5, OS_CONTEXT_SRR1(context)
|
||||
ori r5, r5, 0x2000
|
||||
mtsrr1 r5
|
||||
addis r3, r0, OS_CACHED_REGION_PREFIX
|
||||
lwz r5, 0x00D8(r3)
|
||||
stw context, 0x00D8(r3)
|
||||
cmpw r5, r4
|
||||
beq _restoreAndExit
|
||||
cmpwi r5, 0x0
|
||||
beq _loadNewFPUContext
|
||||
bl __OSSaveFPUContext
|
||||
_loadNewFPUContext:
|
||||
bl __OSLoadFPUContext
|
||||
_restoreAndExit:
|
||||
lwz r3, OS_CONTEXT_CR(context)
|
||||
mtcr r3
|
||||
lwz r3, OS_CONTEXT_LR(context)
|
||||
mtlr r3
|
||||
lwz r3, OS_CONTEXT_SRR0(context)
|
||||
mtsrr0 r3
|
||||
lwz r3, OS_CONTEXT_CTR(context)
|
||||
mtctr r3
|
||||
lwz r3, OS_CONTEXT_XER(context)
|
||||
mtxer r3
|
||||
lhz r3, context->state
|
||||
rlwinm r3, r3, 0, 31, 29
|
||||
sth r3, context->state
|
||||
lwz r5, OS_CONTEXT_R5(context)
|
||||
lwz r3, OS_CONTEXT_R3(context)
|
||||
lwz r4, OS_CONTEXT_R4(context)
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
void __OSContextInit(void) {
|
||||
__OSSetExceptionHandler(__OS_EXCEPTION_FLOATING_POINT, OSSwitchFPUContext);
|
||||
__OSFPUContext = NULL;
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm void OSFillFPUContext(register OSContext* context) {
|
||||
nofralloc
|
||||
mfmsr r5
|
||||
ori r5, r5, 0x2000
|
||||
mtmsr r5
|
||||
isync
|
||||
|
||||
stfd fp0, context->fpr[0]
|
||||
stfd fp1, context->fpr[1]
|
||||
stfd fp2, context->fpr[2]
|
||||
stfd fp3, context->fpr[3]
|
||||
stfd fp4, context->fpr[4]
|
||||
stfd fp5, context->fpr[5]
|
||||
stfd fp6, context->fpr[6]
|
||||
stfd fp7, context->fpr[7]
|
||||
stfd fp8, context->fpr[8]
|
||||
stfd fp9, context->fpr[9]
|
||||
stfd fp10, context->fpr[10]
|
||||
stfd fp11, context->fpr[11]
|
||||
stfd fp12, context->fpr[12]
|
||||
stfd fp13, context->fpr[13]
|
||||
stfd fp14, context->fpr[14]
|
||||
stfd fp15, context->fpr[15]
|
||||
stfd fp16, context->fpr[16]
|
||||
stfd fp17, context->fpr[17]
|
||||
stfd fp18, context->fpr[18]
|
||||
stfd fp19, context->fpr[19]
|
||||
stfd fp20, context->fpr[20]
|
||||
stfd fp21, context->fpr[21]
|
||||
stfd fp22, context->fpr[22]
|
||||
stfd fp23, context->fpr[23]
|
||||
stfd fp24, context->fpr[24]
|
||||
stfd fp25, context->fpr[25]
|
||||
stfd fp26, context->fpr[26]
|
||||
stfd fp27, context->fpr[27]
|
||||
stfd fp28, context->fpr[28]
|
||||
stfd fp29, context->fpr[29]
|
||||
stfd fp30, context->fpr[30]
|
||||
stfd fp31, context->fpr[31]
|
||||
|
||||
mffs fp0
|
||||
stfd fp0, OS_CONTEXT_FPSCR(context)
|
||||
|
||||
lfd fp0, context->fpr[0]
|
||||
|
||||
mfspr r5, HID2
|
||||
rlwinm. r5, r5, 3, 31, 31
|
||||
bc 12, 2, _return
|
||||
|
||||
psq_st fp0, OS_CONTEXT_PSF0(context), 0, 0
|
||||
psq_st fp1, OS_CONTEXT_PSF1(context), 0, 0
|
||||
psq_st fp2, OS_CONTEXT_PSF2(context), 0, 0
|
||||
psq_st fp3, OS_CONTEXT_PSF3(context), 0, 0
|
||||
psq_st fp4, OS_CONTEXT_PSF4(context), 0, 0
|
||||
psq_st fp5, OS_CONTEXT_PSF5(context), 0, 0
|
||||
psq_st fp6, OS_CONTEXT_PSF6(context), 0, 0
|
||||
psq_st fp7, OS_CONTEXT_PSF7(context), 0, 0
|
||||
psq_st fp8, OS_CONTEXT_PSF8(context), 0, 0
|
||||
psq_st fp9, OS_CONTEXT_PSF9(context), 0, 0
|
||||
psq_st fp10, OS_CONTEXT_PSF10(context), 0, 0
|
||||
psq_st fp11, OS_CONTEXT_PSF11(context), 0, 0
|
||||
psq_st fp12, OS_CONTEXT_PSF12(context), 0, 0
|
||||
psq_st fp13, OS_CONTEXT_PSF13(context), 0, 0
|
||||
psq_st fp14, OS_CONTEXT_PSF14(context), 0, 0
|
||||
psq_st fp15, OS_CONTEXT_PSF15(context), 0, 0
|
||||
psq_st fp16, OS_CONTEXT_PSF16(context), 0, 0
|
||||
psq_st fp17, OS_CONTEXT_PSF17(context), 0, 0
|
||||
psq_st fp18, OS_CONTEXT_PSF18(context), 0, 0
|
||||
psq_st fp19, OS_CONTEXT_PSF19(context), 0, 0
|
||||
psq_st fp20, OS_CONTEXT_PSF20(context), 0, 0
|
||||
psq_st fp21, OS_CONTEXT_PSF21(context), 0, 0
|
||||
psq_st fp22, OS_CONTEXT_PSF22(context), 0, 0
|
||||
psq_st fp23, OS_CONTEXT_PSF23(context), 0, 0
|
||||
psq_st fp24, OS_CONTEXT_PSF24(context), 0, 0
|
||||
psq_st fp25, OS_CONTEXT_PSF25(context), 0, 0
|
||||
psq_st fp26, OS_CONTEXT_PSF26(context), 0, 0
|
||||
psq_st fp27, OS_CONTEXT_PSF27(context), 0, 0
|
||||
psq_st fp28, OS_CONTEXT_PSF28(context), 0, 0
|
||||
psq_st fp29, OS_CONTEXT_PSF29(context), 0, 0
|
||||
psq_st fp30, OS_CONTEXT_PSF30(context), 0, 0
|
||||
psq_st fp31, OS_CONTEXT_PSF31(context), 0, 0
|
||||
|
||||
_return:
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
#include <stdio.h>
|
||||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
OSErrorHandler __OSErrorTable[17];
|
||||
|
||||
#define FPSCR_ENABLE (FPSCR_VE | FPSCR_OE | FPSCR_UE | FPSCR_ZE | FPSCR_XE)
|
||||
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, int line, const char* msg, ...) {
|
||||
va_list marker;
|
||||
u32 i;
|
||||
u32* p;
|
||||
|
||||
OSDisableInterrupts();
|
||||
va_start(marker, msg);
|
||||
vprintf(msg, marker);
|
||||
va_end(marker);
|
||||
OSReport(" in \"%s\" on line %d.\n", file, line);
|
||||
|
||||
OSReport("\nAddress: Back Chain LR Save\n");
|
||||
for (i = 0, p = (u32*)OSGetStackPointer(); p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) {
|
||||
OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]);
|
||||
}
|
||||
|
||||
PPCHalt();
|
||||
}
|
||||
|
||||
OSErrorHandler OSSetErrorHandler(OSError error, OSErrorHandler handler) {
|
||||
OSErrorHandler oldHandler;
|
||||
int enabled;
|
||||
|
||||
ASSERTMSGLINE(215, error < 17, "OSSetErrorHandler(): unknown error.");
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
oldHandler = __OSErrorTable[error];
|
||||
__OSErrorTable[error] = handler;
|
||||
|
||||
if (error == __OS_EXCEPTION_FLOATING_POINT_EXCEPTION) {
|
||||
u32 msr;
|
||||
u32 fpscr;
|
||||
OSThread* thread;
|
||||
int i;
|
||||
|
||||
msr = PPCMfmsr();
|
||||
PPCMtmsr(msr | MSR_FP);
|
||||
fpscr = PPCMffpscr();
|
||||
|
||||
if (handler) {
|
||||
for (thread = __OSActiveThreadQueue.head; thread;
|
||||
thread = thread->linkActive.next)
|
||||
{
|
||||
thread->context.srr1 |= MSR_FE0 | MSR_FE1;
|
||||
if ((thread->context.state & OS_CONTEXT_STATE_FPSAVED) == 0) {
|
||||
thread->context.state |= OS_CONTEXT_STATE_FPSAVED;
|
||||
for (i = 0; i < 32; ++i) {
|
||||
*(u64*)&thread->context.fpr[i] = (u64)0xffffffffffffffffLL;
|
||||
*(u64*)&thread->context.psf[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->linkActive.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;
|
||||
}
|
||||
|
||||
volatile OSContext* __OSFPUContext AT_ADDRESS(OS_BASE_CACHED | 0x00D8);
|
||||
|
||||
void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar) {
|
||||
OSTime now;
|
||||
now = OSGetTime();
|
||||
|
||||
if (!(context->srr1 & MSR_RI)) {
|
||||
OSReport("Non-recoverable Exception %d", exception);
|
||||
} else {
|
||||
u32 fpscr;
|
||||
u32 msr;
|
||||
if (exception == __OS_EXCEPTION_PROGRAM && (context->srr1 & (0x80000000 >> 11)) &&
|
||||
__OSErrorTable[__OS_EXCEPTION_FLOATING_POINT_EXCEPTION] != 0)
|
||||
{
|
||||
exception = __OS_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_EXCEPTION_DECREMENTER) {
|
||||
OSLoadContext(context);
|
||||
}
|
||||
OSReport("Unhandled Exception %d", exception);
|
||||
}
|
||||
#if DEBUG
|
||||
OSReport("(%s)", __OSExceptionNames[exception]);
|
||||
#endif
|
||||
OSReport("\n");
|
||||
OSDumpContext(context);
|
||||
OSReport("\nDSISR = 0x%08x DAR = 0x%08x\n", dsisr, dar);
|
||||
OSReport("TB = 0x%016llx\n", now);
|
||||
|
||||
switch(exception) {
|
||||
case __OS_EXCEPTION_DSI:
|
||||
OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access "
|
||||
"invalid address 0x%x (read from DAR)\n",
|
||||
context->srr0, dar);
|
||||
break;
|
||||
case __OS_EXCEPTION_ISI:
|
||||
OSReport("\nAttempted to fetch instruction from invalid address 0x%x "
|
||||
"(read from SRR0)\n",
|
||||
context->srr0);
|
||||
break;
|
||||
case __OS_EXCEPTION_ALIGNMENT:
|
||||
OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access "
|
||||
"unaligned address 0x%x (read from DAR)\n",
|
||||
context->srr0, dar);
|
||||
break;
|
||||
case __OS_EXCEPTION_PROGRAM:
|
||||
OSReport("\nProgram exception : Possible illegal instruction/operation "
|
||||
"at or around 0x%x (read from SRR0)\n",
|
||||
context->srr0, dar);
|
||||
break;
|
||||
case __OS_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();
|
||||
}
|
||||
|
|
@ -0,0 +1,795 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/esp.h>
|
||||
|
||||
#include "__os.h"
|
||||
#include "__dvd.h"
|
||||
|
||||
// extern
|
||||
extern size_t wcslen(const wchar_t *);
|
||||
extern int __DVDLayoutFormat;
|
||||
|
||||
extern volatile u32 BOOT_REGION_START AT_ADDRESS(0x812FDFF0);
|
||||
extern volatile u32 BOOT_REGION_END AT_ADDRESS(0x812FDFEC);
|
||||
extern volatile u8 g_unk_800030E2 AT_ADDRESS(0x800030E2);
|
||||
|
||||
DVDDiskID id;
|
||||
|
||||
static int Prepared;
|
||||
BOOL __OSInReboot;
|
||||
u32 __OSNextPartitionType = 0;
|
||||
|
||||
static int PackArgs(void* addr, s32 argc, char** argv) {
|
||||
s32 numArgs;
|
||||
char* bootInfo2;
|
||||
char* ptr;
|
||||
char** list;
|
||||
u32 i;
|
||||
|
||||
bootInfo2 = (char*)addr;
|
||||
memset(bootInfo2, 0, 0x2000);
|
||||
|
||||
if (argc == 0) {
|
||||
*(u32*)(bootInfo2 + 8) = 0;
|
||||
} else {
|
||||
numArgs = argc;
|
||||
ptr = bootInfo2 + 0x2000;
|
||||
while (--argc >= 0) {
|
||||
ptr -= strlen(argv[argc]) + 1;
|
||||
strcpy(ptr, argv[argc]);
|
||||
argv[argc] = (char*)(ptr - bootInfo2);
|
||||
}
|
||||
|
||||
ptr = bootInfo2 + ((ptr - bootInfo2) & ~0x3);
|
||||
ptr -= ((numArgs + 1) * 4);
|
||||
list = (char**)ptr;
|
||||
|
||||
for (i = 0; i < numArgs + 1; i++) {
|
||||
list[i] = argv[i];
|
||||
}
|
||||
|
||||
ptr -= 4;
|
||||
*(u32*)ptr = numArgs;
|
||||
|
||||
ASSERTMSGLINE(401, ptr - bootInfo2 >= 0x1000U, "OSExec: Argument list is too long");
|
||||
|
||||
*(u32*)(bootInfo2 + 8) = (ptr - bootInfo2);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL Utf16ToArg(char* dstArg, u16* srcName) {
|
||||
char* srcPtr, *dstPtr;
|
||||
u8 i, mask, shift;
|
||||
|
||||
if (srcName != 0) {
|
||||
srcPtr = (char*)srcName;
|
||||
dstPtr = dstArg;
|
||||
|
||||
while (*srcPtr || *(srcPtr + 1)) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
mask = (u8)((i & 0x1) ? 0xF : 0xF0);
|
||||
shift = (u8)((i & 0x1) ? 0 : 4);
|
||||
|
||||
if (0 <= ((*srcPtr & mask) >> shift) && ((*srcPtr & mask) >> shift) < 0xA) {
|
||||
*dstPtr = (char)(((*srcPtr & mask) >> shift) + 0x30);
|
||||
}
|
||||
else if(0xA <= ((*srcPtr & mask) >> shift) && ((*srcPtr & mask) >> shift) < 0x10) {
|
||||
*dstPtr = (char)(((*srcPtr & mask) >> shift) + 0x57);
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dstPtr++;
|
||||
|
||||
if (i & 1) {
|
||||
srcPtr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*dstPtr++ = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL PackInstallerArgs(void* addr, s32 argc, char* argv[]) {
|
||||
s32 numArgs;
|
||||
char* bootInfo2;
|
||||
char* ptr;
|
||||
char** list;
|
||||
u32 i;
|
||||
|
||||
bootInfo2 = (char*)addr;
|
||||
memset(bootInfo2, 0, 0x2000);
|
||||
|
||||
if (argc == 0) {
|
||||
*(u32*)(bootInfo2 + 8) = 0;
|
||||
} else {
|
||||
numArgs = argc;
|
||||
ptr = bootInfo2 + 0x2000;
|
||||
|
||||
while (--argc >= 0) {
|
||||
if (argc < 2 || (argc % 2)) {
|
||||
ptr -= strlen(argv[argc]) + 1;
|
||||
strcpy(ptr, argv[argc]);
|
||||
argv[argc] = (char*)(ptr - bootInfo2);
|
||||
} else {
|
||||
ptr -= (wcslen((u16*)argv[argc]) * 4 + 1);
|
||||
Utf16ToArg(ptr, (u16*)argv[argc]);
|
||||
argv[argc] = (char*)(ptr - bootInfo2);
|
||||
}
|
||||
}
|
||||
|
||||
ptr = bootInfo2 + ((ptr - bootInfo2) & ~0x3);
|
||||
ptr -= ((numArgs + 1) * 4);
|
||||
list = (char**)ptr;
|
||||
|
||||
for (i = 0; i < numArgs + 1; i++) {
|
||||
list[i] = argv[i];
|
||||
}
|
||||
|
||||
ptr -= 4;
|
||||
*(u32*)ptr = numArgs;
|
||||
|
||||
ASSERTMSGLINE(524, ptr - bootInfo2 >= 0x1000U, "OSExec: Argument list is too long");
|
||||
|
||||
*(u32*)(bootInfo2 + 8) = (ptr - bootInfo2);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void Run(register void* entryPoint) {
|
||||
fralloc
|
||||
|
||||
bl ICFlashInvalidate
|
||||
sync
|
||||
isync
|
||||
mtctr entryPoint
|
||||
bctr
|
||||
|
||||
frfree
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
||||
static void StartDol(const OSExecParams* params, void* entry) {
|
||||
OSExecParams* paramsWork = OSAllocFromMEM1ArenaLo(sizeof(OSExecParams), 1);
|
||||
|
||||
__OSSetExecParams(params, paramsWork);
|
||||
__PIRegs[9] = 7;
|
||||
|
||||
OSDisableInterrupts();
|
||||
Run(entry);
|
||||
}
|
||||
|
||||
static void ReadDisc(void* addr, s32 length, s32 offset) {
|
||||
DVDCommandBlock block;
|
||||
// NOTE: unsure what these are, but required to match debug
|
||||
volatile u32 sp18 = 0;
|
||||
u8 sp14[] = {0xFF, 0xFF, 0xFF, 0x00};
|
||||
|
||||
DVDReadAbsAsyncPrio(&block, addr, length, offset, NULL, 0);
|
||||
|
||||
while (DVDGetCommandBlockStatus(&block)) {
|
||||
if (DVDGetCommandBlockStatus(&block) > 2 || DVDGetCommandBlockStatus(&block) < 0) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Callback(s32, DVDCommandBlock*) {
|
||||
Prepared = TRUE;
|
||||
}
|
||||
|
||||
static int IsStreamEnabled() {
|
||||
if (DVDGetCurrentDiskID()->streaming) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void __OSGetExecParams(OSExecParams* params) {
|
||||
if (0x80000000 <= (u32)__OSExecParams) {
|
||||
memcpy(params, __OSExecParams, sizeof(OSExecParams));
|
||||
} else {
|
||||
params->valid = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void __OSSetExecParams(const OSExecParams* params, OSExecParams* addr) {
|
||||
memcpy(addr, params, sizeof(OSExecParams));
|
||||
__OSExecParams = addr;
|
||||
}
|
||||
|
||||
static void StopStreaming() {
|
||||
DVDCommandBlock block;
|
||||
|
||||
if (!__OSIsGcam && IsStreamEnabled()) {
|
||||
AISetStreamVolLeft(0);
|
||||
AISetStreamVolRight(0);
|
||||
DVDCancelStreamAsync(&block, NULL);
|
||||
|
||||
|
||||
while (DVDGetCommandBlockStatus(&block)) {
|
||||
if (!DVDCheckDisk()) {
|
||||
__OSDoHotReset(0);
|
||||
}
|
||||
}
|
||||
|
||||
AISetStreamPlayState(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int GetApploaderPosition(void) {
|
||||
static s32 apploaderPosition;
|
||||
|
||||
if (apploaderPosition != 0) {
|
||||
return apploaderPosition;
|
||||
}
|
||||
|
||||
if (__OSAppLoaderOffset != 0) {
|
||||
u32* tgcHeader;
|
||||
s32 apploaderOffsetInTGC;
|
||||
|
||||
tgcHeader = OSAllocFromMEM1ArenaLo(0x40, DOLPHIN_ALIGNMENT);
|
||||
ReadDisc(tgcHeader, 0x40, __OSAppLoaderOffset >> 2);
|
||||
apploaderOffsetInTGC = tgcHeader[14];
|
||||
ASSERTMSGLINE(727, apploaderOffsetInTGC != 0, "OSExec() or OSResetSystem(): Wrong apploader offset. Maybe converted by an\nolder version of gcm2tgc. Use gcm2tgc v.1.20 or later.");
|
||||
|
||||
apploaderPosition = (__OSAppLoaderOffset + apploaderOffsetInTGC) >> 2;
|
||||
} else {
|
||||
apploaderPosition = 0x910;
|
||||
}
|
||||
|
||||
return apploaderPosition;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char date[16];
|
||||
u32 entry;
|
||||
u32 size;
|
||||
u32 rebootSize;
|
||||
u32 reserved2;
|
||||
} AppLoaderStruct;
|
||||
|
||||
static AppLoaderStruct* LoadApploader() {
|
||||
AppLoaderStruct* header;
|
||||
|
||||
header = (AppLoaderStruct*)OSAllocFromMEM1ArenaLo(sizeof(AppLoaderStruct), DOLPHIN_ALIGNMENT);
|
||||
ReadDisc(header, sizeof(AppLoaderStruct), GetApploaderPosition());
|
||||
ASSERTMSGLINE(758, header->rebootSize != 0, "OSResetSystem(): old apploader");
|
||||
|
||||
ReadDisc((void*)0x81200000, OSRoundUp32B(header->size), GetApploaderPosition() + 0x8);
|
||||
ICInvalidateRange((void*)0x81200000, OSRoundUp32B(header->size));
|
||||
return header;
|
||||
}
|
||||
|
||||
static void* LoadDol(const OSExecParams* params, AppLoaderCallback getInterface) {
|
||||
appInitCallback appInit;
|
||||
appGetNextCallback appGetNext;
|
||||
appGetEntryCallback appGetEntry;
|
||||
void* addr;
|
||||
u32 length;
|
||||
u32 offset;
|
||||
OSExecParams* paramsWork;
|
||||
|
||||
getInterface(&appInit, &appGetNext, &appGetEntry);
|
||||
paramsWork = (OSExecParams*)OSAllocFromMEM1ArenaLo(sizeof(OSExecParams), 1);
|
||||
__OSSetExecParams(params, paramsWork);
|
||||
appInit((void(*)(char*))OSReport);
|
||||
OSSetArenaLo(paramsWork);
|
||||
|
||||
while (appGetNext(&addr, &length, &offset) != 0) {
|
||||
ReadDisc(addr, length, offset >> __DVDLayoutFormat);
|
||||
}
|
||||
|
||||
return appGetEntry();
|
||||
}
|
||||
|
||||
static BOOL IsNewApploader(AppLoaderStruct* header) {
|
||||
if (strncmp(header->date, "2004/02/01", 10) > 0) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 DVDLowIntType;
|
||||
|
||||
static void callback(u32 param_0) {
|
||||
DVDLowIntType = param_0;
|
||||
}
|
||||
|
||||
void CheckDVDLowIntType(int param_0) {
|
||||
switch (param_0) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
OSReport("\nDisc error occurred!\n");
|
||||
__OSReturnToMenuForError();
|
||||
break;
|
||||
case 16:
|
||||
OSReport("\nTimeout error occurred!\n");
|
||||
__OSReturnToMenuForError();
|
||||
break;
|
||||
default:
|
||||
OSReport("\nUnexpected error occurred!\n");
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
}
|
||||
|
||||
// NONMATCHING
|
||||
void __OSLaunchNextFirmware(void) {
|
||||
DVDPartitionInfo* var_r30;
|
||||
int rc = -1;
|
||||
DVDPartitionInfo* var_r28;
|
||||
u32 var_r27;
|
||||
|
||||
u32 ticketCnt = 1;
|
||||
ESSysVersion version = 0x100000003;
|
||||
ESTicketView* sp30;
|
||||
ESTicketView* ticket;
|
||||
|
||||
u32 MEM2Size;
|
||||
u32 MEM2End;
|
||||
DVDGameTOC* gameTOC;
|
||||
DVDPartitionInfo* partitionInfo;
|
||||
ESTitleMeta* meta;
|
||||
u32 tmd = 0;
|
||||
|
||||
gameTOC = OSAllocFromMEM1ArenaLo(0x20, 0x20);
|
||||
partitionInfo = OSAllocFromMEM1ArenaLo(0x800, 0x20);
|
||||
meta = OSAllocFromMEM1ArenaLo(0x4A00, 0x40);
|
||||
ticket = OSAllocFromMEM1ArenaLo(0xE0, 0x20);
|
||||
|
||||
if (__OSNextPartitionType == *(u32*)0x80003194 && *(u32*)OSPhysicalToCached(0x3198) != 0) {
|
||||
rc = ESP_InitLib();
|
||||
if (!rc) {
|
||||
rc = ESP_DiGetTicketView(NULL, ticket);
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
rc = ESP_DiGetTmd(NULL, &tmd);
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
rc = ESP_DiGetTmd(meta, &tmd);
|
||||
}
|
||||
|
||||
ESP_CloseLib();
|
||||
|
||||
if (OSPlayTimeIsLimited()) {
|
||||
__OSPlayTimeType type = OSPLAYTIME_PERMANENT;
|
||||
u32 playTime = -1;
|
||||
__OSGetPlayTime(ticket, &type, &playTime);
|
||||
if (playTime == 0) {
|
||||
__OSWriteExpiredFlag();
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!rc) {
|
||||
var_r30 = partitionInfo;
|
||||
var_r30->type = *(u32*)OSPhysicalToCached(0x3194);
|
||||
var_r30->gamePartition = (DVDGamePartition*)*(u32*)OSPhysicalToCached(0x3198);
|
||||
} else {
|
||||
u8 i;
|
||||
DVDLowIntType = 0;
|
||||
DVDLowClosePartition(callback);
|
||||
while (DVDLowIntType == 0) {}
|
||||
|
||||
CheckDVDLowIntType(DVDLowIntType);
|
||||
DVDLowIntType = 0;
|
||||
DVDLowUnencryptedRead(&gameTOC->numGamePartitions, 0x20, 0x10000, callback);
|
||||
while (DVDLowIntType == 0) {}
|
||||
|
||||
CheckDVDLowIntType(DVDLowIntType);
|
||||
DVDLowIntType = 0;
|
||||
DVDLowUnencryptedRead(partitionInfo, 0x800, (u32)gameTOC->partitionInfos, callback);
|
||||
while (DVDLowIntType == 0) {}
|
||||
|
||||
CheckDVDLowIntType(DVDLowIntType);
|
||||
|
||||
var_r30 = NULL;
|
||||
var_r28 = partitionInfo;
|
||||
|
||||
for (i = 0; i < gameTOC->numGamePartitions; i++) {
|
||||
if (var_r28->type == __OSNextPartitionType) {
|
||||
var_r30 = var_r28;
|
||||
}
|
||||
|
||||
var_r28++;
|
||||
}
|
||||
|
||||
if (var_r30 == 0) {
|
||||
gameTOC++;
|
||||
var_r28 = partitionInfo + 4;
|
||||
|
||||
for (i = 0; i < gameTOC->numGamePartitions; i++) {
|
||||
if (var_r28->type == __OSNextPartitionType) {
|
||||
var_r30 = var_r28;
|
||||
}
|
||||
|
||||
var_r28 += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (var_r30 == 0) {
|
||||
OSReport("\nThe specified game doesn\'t exist in the disc\n");
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
var_r27 = var_r30->type;
|
||||
*(u32*)OSPhysicalToCached(0x3194) = var_r27;
|
||||
|
||||
var_r27 = (u32)var_r30->gamePartition;
|
||||
*(u32*)OSPhysicalToCached(0x3198) = var_r27;
|
||||
|
||||
DVDLowIntType = 0;
|
||||
|
||||
if (*(u8*)0x80003187 == 0x80) {
|
||||
DVDLowOpenPartitionWithTmdAndTicketView((u32)var_r30->gamePartition, ticket, tmd, meta, 0, 0, callback);
|
||||
} else {
|
||||
DVDLowOpenPartition((u32)var_r30->gamePartition, NULL, 0, NULL, meta, callback);
|
||||
}
|
||||
|
||||
while (DVDLowIntType == 0) {}
|
||||
CheckDVDLowIntType(DVDLowIntType);
|
||||
DVDLowIntType = 0;
|
||||
DVDLowClosePartition(callback);
|
||||
|
||||
while (DVDLowIntType == 0) {}
|
||||
CheckDVDLowIntType(DVDLowIntType);
|
||||
}
|
||||
|
||||
version = meta->head.sysVersion;
|
||||
|
||||
rc = ESP_InitLib();
|
||||
if (rc) {
|
||||
OSReport("\nOSExec(): Failed to exec %d in %d\n", rc, 1037);
|
||||
__OSHotResetForError();
|
||||
}
|
||||
|
||||
rc = ESP_GetTicketViews(version, NULL, &ticketCnt);
|
||||
if (ticketCnt != 1 || rc) {
|
||||
OSReport("\nOSExec(): Failed to exec %d in %d\n", rc, 1046);
|
||||
__OSHotResetForError();
|
||||
}
|
||||
|
||||
sp30 = OSAllocFromMEM1ArenaLo(OSRoundUp32B(ticketCnt * sizeof(ESTicketView)), 0x20);
|
||||
rc = ESP_GetTicketViews(version, sp30, &ticketCnt);
|
||||
if (rc) {
|
||||
OSReport("\nOSExec(): Failed to exec %d in %d\n", rc, 1055);
|
||||
__OSHotResetForError();
|
||||
}
|
||||
|
||||
DVDLowFinalize();
|
||||
|
||||
MEM2Size = *(u32*)OSPhysicalToCached(0x311C);
|
||||
MEM2End = *(u32*)OSPhysicalToCached(0x3120);
|
||||
DCStoreRange(OSPhysicalToCached(0x3100), 0x100);
|
||||
|
||||
rc = ESP_LaunchTitle(version, sp30);
|
||||
if (rc) {
|
||||
OSReport("\nOSExec(): Failed to exec %d in %d\n", rc, 1071);
|
||||
__OSHotResetForError();
|
||||
}
|
||||
|
||||
ESP_CloseLib();
|
||||
DCInvalidateRange(OSPhysicalToCached(0x3100), 0x100);
|
||||
|
||||
if (MEM2Size < *(u32*)OSPhysicalToCached(0x311C)) {
|
||||
var_r27 = *(u32*)OSPhysicalToCached(0x311C);
|
||||
var_r27 = MEM2Size - (var_r27 - *(u32*)OSPhysicalToCached(0x3120));
|
||||
*(u32*)OSPhysicalToCached(0x3120) = var_r27;
|
||||
|
||||
var_r27 = *(u32*)OSPhysicalToCached(0x311C);
|
||||
var_r27 = MEM2Size - (var_r27 - *(u32*)OSPhysicalToCached(0x3128));
|
||||
*(u32*)OSPhysicalToCached(0x3128) = var_r27;
|
||||
|
||||
var_r27 = *(u32*)OSPhysicalToCached(0x311C);
|
||||
var_r27 = MEM2Size - (var_r27 - *(u32*)OSPhysicalToCached(0x3130));
|
||||
*(u32*)OSPhysicalToCached(0x3130) = var_r27;
|
||||
|
||||
var_r27 = *(u32*)OSPhysicalToCached(0x311C);
|
||||
var_r27 = MEM2Size - (var_r27 - *(u32*)OSPhysicalToCached(0x3134));
|
||||
*(u32*)OSPhysicalToCached(0x3134) = var_r27;
|
||||
|
||||
var_r27 = MEM2Size;
|
||||
*(u32*)OSPhysicalToCached(0x311C) = var_r27;
|
||||
}
|
||||
|
||||
if (MEM2End < *(u32*)OSPhysicalToCached(0x3120)) {
|
||||
__OSInitMemoryProtection();
|
||||
}
|
||||
|
||||
__OSInitIPCBuffer();
|
||||
IPCReInit();
|
||||
IPCCltReInit();
|
||||
|
||||
DVDLowInit();
|
||||
DVDLowIntType = 0;
|
||||
DVDLowReadDiskID(&id, callback);
|
||||
while (DVDLowIntType == 0) {}
|
||||
CheckDVDLowIntType(DVDLowIntType);
|
||||
DVDLowIntType = 0;
|
||||
|
||||
if (*(u8*)0x80003187 == 0x80) {
|
||||
DVDLowOpenPartitionWithTmdAndTicketView((u32)var_r30->gamePartition, ticket, tmd, meta, 0, 0, callback);
|
||||
} else {
|
||||
DVDLowOpenPartition((u32)var_r30->gamePartition, NULL, 0, NULL, meta, callback);
|
||||
}
|
||||
|
||||
while (DVDLowIntType == 0) {}
|
||||
|
||||
CheckDVDLowIntType(DVDLowIntType);
|
||||
}
|
||||
|
||||
#define TITLE_ID ((((u64)1) << 32) | (2))
|
||||
|
||||
void __OSLaunchMenu(void) {
|
||||
u8 i;
|
||||
s32 rc;
|
||||
u32 ticketCnt = 1;
|
||||
ESTicketView* t;
|
||||
ESSysVersion version = 0x0000000100000003;
|
||||
GXColor bg = { 0, 0, 0, 0};
|
||||
GXColor fg = { 255, 255, 255, 0 };
|
||||
|
||||
OSSetArenaLo((void*)0x81280000);
|
||||
OSSetArenaHi((void*)0x812F0000);
|
||||
rc = ESP_InitLib();
|
||||
|
||||
if (rc != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ESP_GetTicketViews(TITLE_ID, NULL, &ticketCnt);
|
||||
|
||||
if (ticketCnt != 1 || rc != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
t = (ESTicketView*)OSAllocFromMEM1ArenaLo(OSRoundUp32B(sizeof(ESTicketView) * ticketCnt), 32);
|
||||
rc = ESP_GetTicketViews(TITLE_ID, t, &ticketCnt);
|
||||
|
||||
if (rc != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ESP_LaunchTitle(TITLE_ID, t);
|
||||
|
||||
if (rc != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// NONMATCHING - stack issues
|
||||
void __OSBootDolSimple(u32 doloffset, u32 restartCode, void* regionStart, void* regionEnd, BOOL argsUseDefault, s32 argc, char** argv) {
|
||||
OSExecParams* params;
|
||||
void* dolEntry;
|
||||
OSBootInfo* bootInfo;
|
||||
char* sp20;
|
||||
AppLoaderStruct* header;
|
||||
|
||||
OSDisableInterrupts();
|
||||
|
||||
if (__OSInReboot) {
|
||||
__OSNextPartitionType = *(u32*)0x80003194;
|
||||
}
|
||||
|
||||
__OSRestoreCodeExecOnMEM1(0xBA2CF);
|
||||
|
||||
params = (OSExecParams*)OSAllocFromMEM1ArenaLo(sizeof(OSExecParams), 1);
|
||||
params->valid = TRUE;
|
||||
params->restartCode = restartCode;
|
||||
params->regionStart = regionStart;
|
||||
params->regionEnd = regionEnd;
|
||||
params->argsUseDefault = argsUseDefault;
|
||||
|
||||
if (!argsUseDefault) {
|
||||
params->argsAddr = OSAllocFromMEM1ArenaLo(0x2000, 1);
|
||||
|
||||
if (__OSNextPartitionType == 2 && !__OSInReboot) {
|
||||
PackInstallerArgs(params->argsAddr, argc, argv);
|
||||
} else {
|
||||
PackArgs(params->argsAddr, argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
DVDInit();
|
||||
DVDSetAutoInvalidation(TRUE);
|
||||
DVDResume();
|
||||
|
||||
Prepared = FALSE;
|
||||
|
||||
__DVDPrepareResetAsync(Callback);
|
||||
__OSMaskInterrupts(0xFFFFFFF0);
|
||||
__OSUnmaskInterrupts(0x10);
|
||||
OSEnableInterrupts();
|
||||
|
||||
while (Prepared != TRUE) {}
|
||||
|
||||
__OSLaunchNextFirmware();
|
||||
|
||||
if (restartCode == 0xA0000000 && !__OSInReboot) {
|
||||
ESTitleId titleID;
|
||||
int rc;
|
||||
|
||||
rc = ESP_InitLib();
|
||||
if (rc) {
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ESP_GetTitleId(&titleID);
|
||||
if (rc) {
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ESP_CloseLib();
|
||||
if (rc) {
|
||||
return;
|
||||
}
|
||||
|
||||
sp20 = (u32)params->argsAddr + argv[1];
|
||||
snprintf(sp20, 17, "%016llx", titleID);
|
||||
}
|
||||
|
||||
header = LoadApploader();
|
||||
if (IsNewApploader(header)) {
|
||||
if (doloffset == 0xFFFFFFFF) {
|
||||
doloffset = GetApploaderPosition() + ((header->size + 0x20) >> 2);
|
||||
}
|
||||
|
||||
params->bootDol = doloffset;
|
||||
dolEntry = LoadDol(params, (AppLoaderCallback)header->entry);
|
||||
|
||||
bootInfo = OSPhysicalToCached(0);
|
||||
*(u32*)OSPhysicalToCached(0x3180) = *(u32*)bootInfo->DVDDiskID.gameName;
|
||||
*(u8*)OSPhysicalToCached(0x3184) = 0x80;
|
||||
|
||||
StartDol(params, dolEntry);
|
||||
} else {
|
||||
BOOT_REGION_START = (u32)regionStart;
|
||||
BOOT_REGION_END = (u32)regionEnd;
|
||||
g_unk_800030E2 = 1;
|
||||
|
||||
ReadDisc((void*)0x81330000, OSRoundUp32B(header->rebootSize), GetApploaderPosition() + ((header->size + 0x20) >> 2));
|
||||
ICInvalidateRange((void*)0x81330000, OSRoundUp32B(header->rebootSize));
|
||||
OSDisableInterrupts();
|
||||
ICFlashInvalidate();
|
||||
Run((void*)0x81330000);
|
||||
}
|
||||
}
|
||||
|
||||
void __OSBootDol(u32 doloffset, u32 restartCode, const char** argv) {
|
||||
char doloffInString[20];
|
||||
s32 argvlen;
|
||||
char** argvToPass;
|
||||
s32 i;
|
||||
void* saveStart;
|
||||
void* saveEnd;
|
||||
|
||||
OSGetSaveRegion(&saveStart, &saveEnd);
|
||||
sprintf(doloffInString, "%d", doloffset);
|
||||
argvlen = 0;
|
||||
|
||||
if (argv != 0) {
|
||||
while (argv[argvlen] != 0) {
|
||||
argvlen++;
|
||||
}
|
||||
}
|
||||
|
||||
argvlen++;
|
||||
argvToPass = OSAllocFromMEM1ArenaLo((argvlen + 1) * 4, 1);
|
||||
*argvToPass = doloffInString;
|
||||
|
||||
for (i = 1; i < argvlen; i++) {
|
||||
argvToPass[i] = (char*)argv[i - 1];
|
||||
}
|
||||
|
||||
__OSBootDolSimple(-1, restartCode, saveStart, saveEnd, FALSE, argvlen, argvToPass);
|
||||
}
|
||||
|
||||
void OSLaunchDisk(void) {
|
||||
// NOTE: Function doesn't exist in TP debug, but string data is leftover
|
||||
OSReport("OSLaunchDisk(): You can't call this API from DVD application. \n");
|
||||
OSReport("OSLaunchDisk(): You must call DVDPrepareDisk before launching disc.\n");
|
||||
OSReport("OSLaunchDisk(): Specified id is different from one specified to DVDPrepareDisk.\n");
|
||||
}
|
||||
|
||||
void OSLaunchDiskl(void) {
|
||||
// NOTE: Function doesn't exist in TP debug, but string data is leftover
|
||||
OSReport("0000000000000000");
|
||||
OSReport("OSLaunchDiskl(): Arguments too long");
|
||||
}
|
||||
|
||||
static void ExecCommon(const char* dolfile, const char** argv) {
|
||||
DVDFileInfo fileInfo;
|
||||
u32 doloff;
|
||||
|
||||
if ((s8)*dolfile == '\0') {
|
||||
doloff = 0;
|
||||
} else if (DVDOpen((char*)dolfile, &fileInfo)) {
|
||||
doloff = fileInfo.startAddr;
|
||||
} else {
|
||||
ASSERTMSGLINE(0, 0, "Warning: OSExec(): The specified file doesn't exist. \n");
|
||||
return;
|
||||
}
|
||||
|
||||
__OSBootDol(doloff, 0xC0000000, argv);
|
||||
}
|
||||
|
||||
void OSExecv(const char* dolfile, const char** argv) {
|
||||
ASSERTMSGLINE(0, dolfile != 0, "OSExecv(): null pointer was specified for the dol file name.");
|
||||
ASSERTMSGLINE(0, argv != 0, "OSExecv(): null pointer was specified for argv.");
|
||||
|
||||
OSDisableScheduler();
|
||||
__OSShutdownDevices(FALSE);
|
||||
OSEnableScheduler();
|
||||
OSSetArenaLo((void*)0x81280000);
|
||||
OSSetArenaHi((void*)0x812F0000);
|
||||
ExecCommon(dolfile, argv);
|
||||
}
|
||||
|
||||
void OSExecl(const char* dolfile, const char* arg0, ...) {
|
||||
va_list vl;
|
||||
char* ptr;
|
||||
s32 i;
|
||||
char** argv;
|
||||
|
||||
ASSERTMSGLINE(0, dolfile != 0, "OSExecl(): null pointer was specified for the dol file name.");
|
||||
|
||||
OSDisableScheduler();
|
||||
__OSShutdownDevices(FALSE);
|
||||
OSEnableScheduler();
|
||||
OSSetArenaLo((void*)0x81280000);
|
||||
OSSetArenaHi((void*)0x812F0000);
|
||||
|
||||
argv = OSAllocFromMEM1ArenaLo(4, 0x1000);
|
||||
va_start(vl, arg0);
|
||||
|
||||
i = 0;
|
||||
ptr = (char*)arg0;
|
||||
goto setarg;
|
||||
|
||||
do {
|
||||
ptr = va_arg(vl, char*);
|
||||
setarg:
|
||||
argv[i++] = ptr;
|
||||
} while (ptr != 0);
|
||||
|
||||
va_end(vl);
|
||||
ASSERTMSGLINE(0, i < 0x400U, "OSExecl(): Arguments too long");
|
||||
|
||||
ExecCommon(dolfile, (const char**)argv);
|
||||
}
|
||||
|
||||
void OSLaunchPartition(void) {
|
||||
// NOTE: Function doesn't exist in TP debug, but string data is leftover
|
||||
OSReport("OSLaunchPartition(): You can't call this API from NAND application. \n");
|
||||
OSReport("OSLaunchPartition(): Specified title ID is not DISC application. \n");
|
||||
OSReport("/title/%08x/%08x");
|
||||
OSReport("\nOSLaunchPartition(): Failed to get free i-nodes number\n");
|
||||
OSReport("\nOSLaunchPartition(): There are not enough i-nodes to launch next partition\n");
|
||||
OSReport("\nOSLaunchPartition(): Failed to get nand status\n");
|
||||
}
|
||||
|
||||
void OSLaunchPartitionl(void) {
|
||||
// NOTE: Function doesn't exist in TP debug, but string data is leftover
|
||||
OSReport("OSLaunchPartitionl(): Arguments too long");
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/gx.h>
|
||||
#include <revolution/exi.h>
|
||||
|
||||
#include "__os.h"
|
||||
#include <string.h>
|
||||
|
||||
typedef struct OSFatalParam {
|
||||
GXColor fg;
|
||||
GXColor bg;
|
||||
const char* msg;
|
||||
} OSFatalParam;
|
||||
|
||||
static OSFatalParam FatalParam;
|
||||
static OSContext FatalContext;
|
||||
|
||||
// prototypes
|
||||
static void Halt();
|
||||
|
||||
static void ScreenClear(void* xfb, u16 xfbW, u16 xfbH, GXColor yuv) {
|
||||
int i;
|
||||
int j;
|
||||
u8* ptr;
|
||||
|
||||
ptr = xfb;
|
||||
for (i = 0; i < xfbH; i++) {
|
||||
for (j = 0; j < xfbW; j += 2) {
|
||||
*ptr++ = yuv.r;
|
||||
*ptr++ = yuv.g;
|
||||
*ptr++ = yuv.r;
|
||||
*ptr++ = yuv.b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ScreenReport(void* xfb, u16 xfbW, u16 xfbH, GXColor yuv, s32 x, s32 y, s32 leading, const char* string) {
|
||||
u8* ptr;
|
||||
s32 width;
|
||||
u32 i;
|
||||
u32 j;
|
||||
u32 image[72];
|
||||
u32 k;
|
||||
u32 l;
|
||||
u8 Y;
|
||||
u32 pixel;
|
||||
s32 col;
|
||||
|
||||
loop_1:
|
||||
if (xfbH - 24 >= y) {
|
||||
ptr = (u8*)xfb + ((x + (y * xfbW)) * 2);
|
||||
col = x;
|
||||
|
||||
while ((s8)*string != 0) {
|
||||
if ((s8)*string == '\n') {
|
||||
string++;
|
||||
y += leading;
|
||||
goto loop_1;
|
||||
}
|
||||
|
||||
if (xfbW - 48 < col) {
|
||||
y += leading;
|
||||
goto loop_1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 24; i++) {
|
||||
j = (i & 7) + ((i >> 3) * 24);
|
||||
image[j + 0 ] = 0;
|
||||
image[j + 8 ] = 0;
|
||||
image[j + 16] = 0;
|
||||
}
|
||||
|
||||
string = OSGetFontTexel((char*)string, image, 0, 6, &width);
|
||||
|
||||
for (i = 0; i < 24; i++) {
|
||||
j = (i & 7) + ((i >> 3) * 24);
|
||||
|
||||
for (k = 0; k < 24; k++) {
|
||||
l = j + 8 * (k / 8);
|
||||
|
||||
Y = (image[l] >> ((7 - (k & 7)) * 4)) & 0xF;
|
||||
if (Y != 0) {
|
||||
Y = (((yuv.r * (Y * 0xEF)) / 255) / 15) + 0x10;
|
||||
pixel = k + (i * xfbW);
|
||||
ptr[pixel * 2] = Y;
|
||||
|
||||
if ((col + k) & 1) {
|
||||
ptr[(pixel * 2) - 1] = yuv.g;
|
||||
ptr[(pixel * 2) + 1] = yuv.b;
|
||||
} else {
|
||||
ptr[(pixel * 2) - 1] = yuv.b;
|
||||
ptr[(pixel * 2) + 1] = yuv.g;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr += width * 2;
|
||||
col += width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConfigureVideo(u16 xfbW, u16 xfbH) {
|
||||
GXRenderModeObj mode;
|
||||
mode.fbWidth = xfbW;
|
||||
mode.efbHeight = 480;
|
||||
mode.xfbHeight = xfbH;
|
||||
mode.viXOrigin = 40;
|
||||
mode.viWidth = 640;
|
||||
mode.viHeight = xfbH;
|
||||
|
||||
switch (VIGetTvFormat()) {
|
||||
case 2:
|
||||
case 0:
|
||||
if (__VIRegs[54] & 1) {
|
||||
mode.viTVmode = 2;
|
||||
mode.viYOrigin = 0;
|
||||
mode.xFBmode = 0;
|
||||
} else {
|
||||
mode.viTVmode = 0;
|
||||
mode.viYOrigin = 0;
|
||||
mode.xFBmode = 1;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (__VIRegs[54] & 1) {
|
||||
mode.viTVmode = 22;
|
||||
mode.viYOrigin = 0;
|
||||
mode.xFBmode = 0;
|
||||
} else {
|
||||
mode.viTVmode = 20;
|
||||
mode.viYOrigin = 0;
|
||||
mode.xFBmode = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
mode.viTVmode = 4;
|
||||
mode.viYOrigin = 47;
|
||||
mode.xFBmode = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
VIConfigure(&mode);
|
||||
VIConfigurePan(0, 0, 640, 480);
|
||||
}
|
||||
|
||||
static GXColor RGB2YUV(GXColor rgb) {
|
||||
f32 Y;
|
||||
f32 Cb;
|
||||
f32 Cr;
|
||||
GXColor yuv;
|
||||
|
||||
Y = 0.5f + (16.0f + ((0.098f * (f32) rgb.b) + ((0.257f * (f32) rgb.r) + (0.504f * (f32) rgb.g))));
|
||||
Cb = 0.5f + (128.0f + ((0.439f * (f32) rgb.b) + ((-0.148f * (f32) rgb.r) - (0.291f * (f32) rgb.g))));
|
||||
Cr = 0.5f + (128.0f + (((0.439f * (f32) rgb.r) - (0.368f * (f32) rgb.g)) - (0.071f * (f32) rgb.b)));
|
||||
|
||||
yuv.r = (Y > 235.0f) ? 235.0f : (Y < 16.0f) ? 16.0f : Y;
|
||||
yuv.g = (Cb > 240.0f) ? 240.0f : (Cb < 16.0f) ? 16.0f : Cb;
|
||||
yuv.b = (Cr > 240.0f) ? 240.0f : (Cr < 16.0f) ? 16.0f : Cr;
|
||||
yuv.a = 0;
|
||||
|
||||
return yuv;
|
||||
}
|
||||
|
||||
void OSFatal(GXColor fg, GXColor bg, const char* msg) {
|
||||
OSBootInfo* bootInfo;
|
||||
u32 count;
|
||||
OSTime t;
|
||||
|
||||
bootInfo = (OSBootInfo*)OSPhysicalToCached(0);
|
||||
OSDisableInterrupts();
|
||||
OSDisableScheduler();
|
||||
OSClearContext(&FatalContext);
|
||||
OSSetCurrentContext(&FatalContext);
|
||||
__OSStopAudioSystem();
|
||||
VIInit();
|
||||
__OSUnmaskInterrupts(0x80);
|
||||
VISetBlack(TRUE);
|
||||
VIFlush();
|
||||
VISetPreRetraceCallback(NULL);
|
||||
VISetPostRetraceCallback(NULL);
|
||||
OSEnableInterrupts();
|
||||
|
||||
count = VIGetRetraceCount();
|
||||
do {} while ((s32)(VIGetRetraceCount() - count) < 1);
|
||||
|
||||
t = OSGetTime();
|
||||
while (!__OSCallShutdownFunctions(FALSE, 0) && OSGetTime() - t < OSMillisecondsToTicks(1000)) {}
|
||||
|
||||
OSDisableInterrupts();
|
||||
__OSCallShutdownFunctions(TRUE, 0);
|
||||
EXISetExiCallback(0, NULL);
|
||||
EXISetExiCallback(2, NULL);
|
||||
|
||||
while (!EXILock(0, 1, NULL)) {
|
||||
EXISync(0);
|
||||
EXIDeselect(0);
|
||||
EXIUnlock(0);
|
||||
}
|
||||
EXIUnlock(0);
|
||||
|
||||
do {} while ((__EXIRegs[3] & 1) == 1);
|
||||
|
||||
__OSSetExceptionHandler(8, &OSDefaultExceptionHandler);
|
||||
GXAbortFrame();
|
||||
OSSetArenaLo((void*)0x81400000);
|
||||
|
||||
if (!bootInfo->FSTLocation) {
|
||||
OSSetArenaHi(*(void**)OSPhysicalToCached(0x3110));
|
||||
} else {
|
||||
OSSetArenaHi(bootInfo->FSTLocation);
|
||||
}
|
||||
|
||||
FatalParam.fg = fg;
|
||||
FatalParam.bg = bg;
|
||||
FatalParam.msg = msg;
|
||||
OSSwitchFiber((u32)&Halt, (u32)OSGetArenaHi());
|
||||
}
|
||||
|
||||
static void Halt() {
|
||||
u32 count;
|
||||
OSFontHeader* fontData;
|
||||
void* xfb;
|
||||
u32 len;
|
||||
OSFatalParam* fp;
|
||||
|
||||
OSEnableInterrupts();
|
||||
fp = &FatalParam;
|
||||
len = strlen(fp->msg) + 1;
|
||||
fp->msg = memmove(OSAllocFromMEM1ArenaLo(len, DOLPHIN_ALIGNMENT), fp->msg, len);
|
||||
|
||||
fontData = OSAllocFromMEM1ArenaLo(0xA1004, DOLPHIN_ALIGNMENT);
|
||||
OSLoadFont(fontData, OSGetArenaLo());
|
||||
|
||||
xfb = OSAllocFromMEM1ArenaLo(0x96000, DOLPHIN_ALIGNMENT);
|
||||
ScreenClear(xfb, 640, 480, RGB2YUV(fp->bg));
|
||||
VISetNextFrameBuffer(xfb);
|
||||
ConfigureVideo(640, 480);
|
||||
VIFlush();
|
||||
|
||||
count = VIGetRetraceCount();
|
||||
do {} while ((s32)(VIGetRetraceCount() - count) < 2);
|
||||
|
||||
ScreenReport(xfb, 640, 480, RGB2YUV(fp->fg), 48, 100, fontData->leading, fp->msg);
|
||||
DCFlushRange(xfb, 0x96000);
|
||||
VISetBlack(FALSE);
|
||||
VIFlush();
|
||||
|
||||
count = VIGetRetraceCount();
|
||||
do {} while ((s32)(VIGetRetraceCount() - count) < 1);
|
||||
|
||||
OSDisableInterrupts();
|
||||
OSReport("%s\n", fp->msg);
|
||||
PPCHalt();
|
||||
}
|
||||
|
|
@ -0,0 +1,748 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
typedef char* (*ParseStringCallback)(u16, char*, OSFontHeader**, int*);
|
||||
|
||||
static OSFontHeader* FontDataAnsi;
|
||||
static OSFontHeader* FontDataSjis;
|
||||
static int FixedPitch;
|
||||
static ParseStringCallback ParseString;
|
||||
static u16 FontEncode = 0xFFFF;
|
||||
|
||||
// prototypes
|
||||
static char* ParseStringS(u16 encode, const char* string, OSFontHeader** pfont, int* pfontCode);
|
||||
static char* ParseStringW(u16 encode, const char* string, OSFontHeader** pfont, int* pfontCode);
|
||||
|
||||
static u16 HankakuToCode[]
|
||||
= { 0x20C, 0x20D, 0x20E, 0x20F, 0x210, 0x211, 0x212, 0x213,
|
||||
0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21A, 0x21B,
|
||||
0x21C, 0x21D, 0x21E, 0x21F, 0x220, 0x221, 0x222, 0x223,
|
||||
0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22A, 0x22B,
|
||||
0x22C, 0x22D, 0x22E, 0x22F, 0x230, 0x231, 0x232, 0x233,
|
||||
0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23A, 0x23B,
|
||||
0x23C, 0x23D, 0x23E, 0x23F, 0x240, 0x241, 0x242, 0x243,
|
||||
0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24A, 0x24B,
|
||||
0x24C, 0x24D, 0x24E, 0x24F, 0x250, 0x251, 0x252, 0x253,
|
||||
0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B,
|
||||
0x25C, 0x25D, 0x25E, 0x25F, 0x260, 0x261, 0x262, 0x263,
|
||||
0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x20C,
|
||||
0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C,
|
||||
0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C,
|
||||
0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C,
|
||||
0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C,
|
||||
0x20C, 0x26B, 0x26C, 0x26D, 0x26E, 0x26F, 0x270, 0x271,
|
||||
0x272, 0x273, 0x274, 0x275, 0x276, 0x277, 0x278, 0x279,
|
||||
0x27A, 0x27B, 0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281,
|
||||
0x282, 0x283, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289,
|
||||
0x28A, 0x28B, 0x28C, 0x28D, 0x28E, 0x28F, 0x290, 0x291,
|
||||
0x292, 0x293, 0x294, 0x295, 0x296, 0x297, 0x298, 0x299,
|
||||
0x29A, 0x29B, 0x29C, 0x29D, 0x29E, 0x29F, 0x2A0, 0x2A1,
|
||||
0x2A2, 0x2A3, 0x2A4, 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9,
|
||||
};
|
||||
|
||||
static u16 Zenkaku2Code[]
|
||||
= { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
|
||||
0x008, 0x009, 0x00A, 0x00B, 0x00C, 0x00D, 0x00E, 0x00F,
|
||||
0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017,
|
||||
0x018, 0x019, 0x01A, 0x01B, 0x01C, 0x01D, 0x01E, 0x01F,
|
||||
0x020, 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x027,
|
||||
0x028, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F,
|
||||
0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037,
|
||||
0x038, 0x039, 0x03A, 0x03B, 0x03C, 0x03D, 0x03E,
|
||||
0x03F, 0x040, 0x041, 0x042, 0x043, 0x044, 0x045, 0x046,
|
||||
0x047, 0x048, 0x049, 0x04A, 0x04B, 0x04C, 0x04D, 0x04E,
|
||||
0x04F, 0x050, 0x051, 0x052, 0x053, 0x054, 0x055, 0x056,
|
||||
0x057, 0x058, 0x059, 0x05A, 0x05B, 0x05C, 0x05D, 0x05E,
|
||||
0x05F, 0x060, 0x061, 0x062, 0x063, 0x064, 0x065, 0x066,
|
||||
0x067, 0x068, 0x069, 0x06A, 0x06B, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x06C, 0x06D, 0x06E, 0x06F, 0x070, 0x071, 0x072, 0x073,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x074, 0x075, 0x076, 0x077, 0x078, 0x079, 0x07A, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x07B, 0x07C, 0x07D, 0x07E, 0x07F, 0x080,
|
||||
0x081, 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, 0x088,
|
||||
0x089, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x08A, 0x08B, 0x08C, 0x08D, 0x08E, 0x08F, 0x090, 0x091,
|
||||
0x000, 0x000, 0x000, 0x000, 0x092,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x093,
|
||||
0x094, 0x095, 0x096, 0x097, 0x098, 0x099, 0x09A, 0x09B,
|
||||
0x09C, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x09D, 0x09E, 0x09F, 0x0A0, 0x0A1, 0x0A2, 0x0A3, 0x0A4,
|
||||
0x0A5, 0x0A6, 0x0A7, 0x0A8, 0x0A9, 0x0AA, 0x0AB, 0x0AC,
|
||||
0x0AD, 0x0AE, 0x0AF, 0x0B0, 0x0B1, 0x0B2, 0x0B3, 0x0B4,
|
||||
0x0B5, 0x0B6, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x0B7, 0x0B8, 0x0B9, 0x0BA, 0x0BB, 0x0BC, 0x0BD,
|
||||
0x0BE, 0x0BF, 0x0C0, 0x0C1, 0x0C2, 0x0C3, 0x0C4, 0x0C5,
|
||||
0x0C6, 0x0C7, 0x0C8, 0x0C9, 0x0CA, 0x0CB, 0x0CC, 0x0CD,
|
||||
0x0CE, 0x0CF, 0x0D0, 0x000, 0x000, 0x000, 0x000, 0x0D1,
|
||||
0x0D2, 0x0D3, 0x0D4, 0x0D5, 0x0D6, 0x0D7, 0x0D8, 0x0D9,
|
||||
0x0DA, 0x0DB, 0x0DC, 0x0DD, 0x0DE, 0x0DF, 0x0E0, 0x0E1,
|
||||
0x0E2, 0x0E3, 0x0E4, 0x0E5, 0x0E6, 0x0E7, 0x0E8, 0x0E9,
|
||||
0x0EA, 0x0EB, 0x0EC, 0x0ED, 0x0EE, 0x0EF, 0x0F0, 0x0F1,
|
||||
0x0F2, 0x0F3, 0x0F4, 0x0F5, 0x0F6, 0x0F7, 0x0F8, 0x0F9,
|
||||
0x0FA, 0x0FB, 0x0FC, 0x0FD, 0x0FE, 0x0FF, 0x100, 0x101,
|
||||
0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109,
|
||||
0x10A, 0x10B, 0x10C, 0x10D, 0x10E, 0x10F, 0x110, 0x111,
|
||||
0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119,
|
||||
0x11A, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121,
|
||||
0x122, 0x123, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12A, 0x12B,
|
||||
0x12C, 0x12D, 0x12E, 0x12F, 0x130, 0x131, 0x132, 0x133,
|
||||
0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13A, 0x13B,
|
||||
0x13C, 0x13D, 0x13E, 0x13F, 0x140, 0x141, 0x142, 0x143,
|
||||
0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A, 0x14B,
|
||||
0x14C, 0x14D, 0x14E, 0x14F, 0x150, 0x151, 0x152, 0x153,
|
||||
0x154, 0x155, 0x156, 0x157, 0x158, 0x159, 0x15A, 0x15B,
|
||||
0x15C, 0x15D, 0x15E, 0x15F, 0x160, 0x161, 0x162,
|
||||
0x163, 0x164, 0x165, 0x166, 0x167, 0x168, 0x169, 0x16A,
|
||||
0x16B, 0x16C, 0x16D, 0x16E, 0x16F, 0x170, 0x171, 0x172,
|
||||
0x173, 0x174, 0x175, 0x176, 0x177, 0x178, 0x179, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x17A,
|
||||
0x17B, 0x17C, 0x17D, 0x17E, 0x17F, 0x180, 0x181, 0x182,
|
||||
0x183, 0x184, 0x185, 0x186, 0x187, 0x188, 0x189, 0x18A,
|
||||
0x18B, 0x18C, 0x18D, 0x18E, 0x18F, 0x190, 0x191, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x192,
|
||||
0x193, 0x194, 0x195, 0x196, 0x197, 0x198, 0x199, 0x19A,
|
||||
0x19B, 0x19C, 0x19D, 0x19E, 0x19F, 0x1A0, 0x1A1, 0x1A2,
|
||||
0x1A3, 0x1A4, 0x1A5, 0x1A6, 0x1A7, 0x1A8, 0x1A9, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x1AA, 0x1AB, 0x1AC, 0x1AD, 0x1AE, 0x1AF, 0x1B0, 0x1B1,
|
||||
0x1B2, 0x1B3, 0x1B4, 0x1B5, 0x1B6, 0x1B7, 0x1B8, 0x1B9,
|
||||
0x1BA, 0x1BB, 0x1BC, 0x1BD, 0x1BE, 0x1BF, 0x1C0, 0x1C1,
|
||||
0x1C2, 0x1C3, 0x1C4, 0x1C5, 0x1C6, 0x1C7, 0x1C8, 0x1C9,
|
||||
0x1CA, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x1CB, 0x1CC, 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2,
|
||||
0x1D3, 0x1D4, 0x1D5, 0x1D6, 0x1D7, 0x1D8, 0x1D9,
|
||||
0x1DA, 0x1DB, 0x1DC, 0x1DD, 0x1DE, 0x1DF, 0x1E0, 0x1E1,
|
||||
0x1E2, 0x1E3, 0x1E4, 0x1E5, 0x1E6, 0x1E7, 0x1E8, 0x1E9,
|
||||
0x1EA, 0x1EB, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x1EC,
|
||||
0x1ED, 0x1EE, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4,
|
||||
0x1F5, 0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC,
|
||||
0x1FD, 0x1FE, 0x1FF, 0x200, 0x201, 0x202, 0x203, 0x204,
|
||||
0x205, 0x206, 0x207, 0x208, 0x209, 0x20A, 0x20B, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x20C,
|
||||
0x20D, 0x20E, 0x20F, 0x210, 0x211, 0x212, 0x213, 0x214,
|
||||
0x215, 0x216, 0x217, 0x218, 0x219, 0x21A, 0x21B, 0x21C,
|
||||
0x21D, 0x21E, 0x21F, 0x220, 0x221, 0x222, 0x223, 0x224,
|
||||
0x225, 0x226, 0x227, 0x228, 0x229, 0x22A, 0x22B, 0x22C,
|
||||
0x22D, 0x22E, 0x22F, 0x230, 0x231, 0x232, 0x233, 0x234,
|
||||
0x235, 0x236, 0x237, 0x238, 0x239, 0x23A, 0x23B, 0x23C,
|
||||
0x23D, 0x23E, 0x23F, 0x240, 0x241, 0x242, 0x243, 0x244,
|
||||
0x245, 0x246, 0x247, 0x248, 0x249, 0x24A, 0x24B,
|
||||
0x24C, 0x24D, 0x24E, 0x24F, 0x250, 0x251, 0x252, 0x253,
|
||||
0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B,
|
||||
0x25C, 0x25D, 0x25E, 0x25F, 0x260, 0x261, 0x262, 0x263,
|
||||
0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x26B,
|
||||
0x26C, 0x26D, 0x26E, 0x26F, 0x270, 0x271, 0x272, 0x273,
|
||||
0x274, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27A, 0x27B,
|
||||
0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, 0x282, 0x283,
|
||||
0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28A, 0x28B,
|
||||
0x28C, 0x28D, 0x28E, 0x28F, 0x290, 0x291, 0x292, 0x293,
|
||||
0x294, 0x295, 0x296, 0x297, 0x298, 0x299, 0x29A, 0x29B,
|
||||
0x29C, 0x29D, 0x29E, 0x29F, 0x2A0, 0x2A1, 0x2A2, 0x2A3,
|
||||
0x2A4, 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9, 0x2AA, 0x2AB,
|
||||
0x2AC, 0x2AD, 0x2AE, 0x2AF, 0x2B0, 0x2B1, 0x2B2, 0x2B3,
|
||||
0x2B4, 0x2B5, 0x2B6, 0x2B7, 0x2B8, 0x2B9, 0x2BA, 0x2BB,
|
||||
0x2BC, 0x2BD, 0x2BE, 0x2BF, 0x2C0, 0x2C1, 0x2C2, 0x2C3,
|
||||
0x2C4, 0x2C5, 0x2C6, 0x2C7, 0x2C8,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x2C9, 0x2CA, 0x2CB, 0x2CC, 0x2CD, 0x2CE, 0x2CF, 0x2D0,
|
||||
0x2D1, 0x2D2, 0x2D3, 0x2D4, 0x2D5, 0x2D6, 0x2D7, 0x2D8,
|
||||
0x2D9, 0x2DA, 0x2DB, 0x2DC, 0x2DD, 0x2DE, 0x2DF, 0x2E0,
|
||||
0x2E1, 0x2E2, 0x2E3, 0x2E4, 0x2E5, 0x2E6, 0x000, 0x2E7,
|
||||
0x2E8, 0x2E9, 0x2EA, 0x2EB, 0x2EC, 0x2ED, 0x2EE, 0x2EF,
|
||||
0x2F0, 0x2F1, 0x2F2, 0x2F3, 0x2F4, 0x2F5, 0x2F6, 0x2F7,
|
||||
0x2F8, 0x2F9, 0x2FA, 0x2FB, 0x2FC, 0x2FD, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x2FE,
|
||||
0x2FF, 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x306,
|
||||
0x307, 0x308, 0x309, 0x30A, 0x30B, 0x30C, 0x30D, 0x30E,
|
||||
0x30F, 0x310, 0x311, 0x312, 0x313, 0x314, 0x315, 0x316,
|
||||
0x317, 0x318, 0x319, 0x31A, 0x31B, 0x000
|
||||
};
|
||||
|
||||
static BOOL IsSjisLeadByte(u8 c) {
|
||||
return (0x81 <= c && c <= 0x9F) || (0xE0 <= c && c <= 0xFC);
|
||||
}
|
||||
|
||||
static BOOL IsSjisTrailByte(u8 c) {
|
||||
return (0x40 <= c && c <= 0xFC) && (c != 0x7F);
|
||||
}
|
||||
|
||||
static int GetFontCode(u16 encode, u16 code) {
|
||||
if (encode == OS_FONT_ENCODE_SJIS) {
|
||||
if (code >= 0x20 && code <= 0xDF) {
|
||||
return HankakuToCode[code - 0x20];
|
||||
}
|
||||
|
||||
if (code > 0x889E && code <= 0x9872) {
|
||||
int i = ((code >> 8) - 0x88) * 188;
|
||||
int j = (code & 0xFF);
|
||||
|
||||
if (!IsSjisTrailByte(j)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
j -= 0x40;
|
||||
if (j >= 0x40) {
|
||||
j--;
|
||||
}
|
||||
|
||||
return (i + j + 0x2BE);
|
||||
}
|
||||
|
||||
if (code >= 0x8140 && code < 0x879E) {
|
||||
int i = ((code >> 8) - 0x81) * 188;
|
||||
int j = (code & 0xFF);
|
||||
|
||||
if (!IsSjisTrailByte(j)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
j -= 0x40;
|
||||
if (j >= 0x40) {
|
||||
j--;
|
||||
}
|
||||
|
||||
return Zenkaku2Code[i + j];
|
||||
}
|
||||
} else if (code > 0x20 && code <= 0xFF) {
|
||||
return code - 0x20;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Decode(u8* s, u8* d) {
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
int p;
|
||||
int q;
|
||||
int r7; // huh? DWARF info says these 2 variables might be register names and not actual names.
|
||||
int r25;
|
||||
int cnt;
|
||||
int os;
|
||||
unsigned int flag;
|
||||
unsigned int code;
|
||||
|
||||
os = *(int*)(s + 0x4);
|
||||
r7 = *(int*)(s + 0x8);
|
||||
r25 = *(int*)(s + 0xC);
|
||||
|
||||
q = 0;
|
||||
flag = 0;
|
||||
p = 16;
|
||||
|
||||
do {
|
||||
// Get next mask
|
||||
if (flag == 0) {
|
||||
code = *(u32*)(s + p);
|
||||
p += sizeof(u32);
|
||||
flag = sizeof(u32) * 8;
|
||||
}
|
||||
|
||||
// Non-linked chunk
|
||||
if (code & 0x80000000) {
|
||||
d[q++] = s[r25++];
|
||||
}
|
||||
// Linked chunk
|
||||
else {
|
||||
// Read offset from link table
|
||||
j = s[r7] << 8 | s[r7 + 1];
|
||||
r7 += sizeof(u16);
|
||||
|
||||
// Apply offset
|
||||
k = q - (j & 0x0FFF);
|
||||
cnt = j >> 12;
|
||||
if (cnt == 0) {
|
||||
cnt = s[r25++] + 0x12;
|
||||
} else {
|
||||
cnt += 2;
|
||||
}
|
||||
|
||||
// Copy chunk
|
||||
for (i = 0; i < cnt; i++, q++, k++) {
|
||||
d[q] = d[k - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare next mask bit
|
||||
code <<= 1;
|
||||
flag--;
|
||||
} while (q < os);
|
||||
}
|
||||
|
||||
static u32 GetFontSize(u8* buf) {
|
||||
if (buf[0] == 'Y' && buf[1] == 'a' && buf[2] == 'y') {
|
||||
return *(u32*)(buf + 0x4);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 OSGetFontEncode(void) {
|
||||
if (FontEncode != 0xFFFF) {
|
||||
return FontEncode;
|
||||
}
|
||||
|
||||
switch (*(int*)OSPhysicalToCached(0xCC)) {
|
||||
case VI_NTSC:
|
||||
FontEncode = (__VIRegs[VI_DTV_STAT] & 2) ? OS_FONT_ENCODE_SJIS : OS_FONT_ENCODE_ANSI;
|
||||
break;
|
||||
case VI_PAL:
|
||||
case VI_MPAL:
|
||||
default:
|
||||
FontEncode = OS_FONT_ENCODE_ANSI;
|
||||
}
|
||||
|
||||
ParseString = (ParseStringCallback)ParseStringS;
|
||||
return FontEncode;
|
||||
}
|
||||
|
||||
u16 OSSetFontEncode(u16 encode) {
|
||||
u16 prev;
|
||||
|
||||
ASSERTLINE(484, encode <= OS_FONT_ENCODE_MAX);
|
||||
|
||||
prev = OSGetFontEncode();
|
||||
if (encode <= OS_FONT_ENCODE_MAX) {
|
||||
FontEncode = encode;
|
||||
if (encode >= 3 && encode <= OS_FONT_ENCODE_MAX) {
|
||||
ParseString = (ParseStringCallback)ParseStringW;
|
||||
}
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
static void ReadROM(void* buf, int length, int offset) {
|
||||
int len;
|
||||
while (length > 0) {
|
||||
len = (length <= 0x100) ? length : 0x100;
|
||||
length -= len;
|
||||
|
||||
while (!__OSReadROM(buf, len, offset)) {
|
||||
;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
(u8*)buf += len;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 ReadFont(void* img, u16 encode, void* fontData) {
|
||||
u32 size;
|
||||
#ifndef DEBUG
|
||||
u32 padding[1];
|
||||
#endif
|
||||
|
||||
if (encode == OS_FONT_ENCODE_SJIS) {
|
||||
ReadROM(img, OS_FONT_ROM_SIZE_SJIS, 0x1AFF00);
|
||||
} else {
|
||||
ReadROM(img, OS_FONT_ROM_SIZE_ANSI, 0x1FCF00);
|
||||
}
|
||||
|
||||
size = GetFontSize(img);
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Decode(img, fontData);
|
||||
if (encode == OS_FONT_ENCODE_SJIS) {
|
||||
OSFontHeader* font = (OSFontHeader*)fontData;
|
||||
int fontCode;
|
||||
u8* imageSrc;
|
||||
int sheet;
|
||||
int numChars;
|
||||
int row;
|
||||
int column;
|
||||
int x;
|
||||
int y;
|
||||
u8* src;
|
||||
const u16 imageT[4] = {0x2ABE, 0x003D, 0x003D, 0x003D};
|
||||
|
||||
fontCode = GetFontCode(encode, 0x54);
|
||||
sheet = fontCode / (font->sheetColumn * font->sheetRow);
|
||||
numChars = fontCode - (sheet * (font->sheetColumn * font->sheetRow));
|
||||
row = numChars / font->sheetColumn;
|
||||
column = numChars - (row * font->sheetColumn);
|
||||
row *= font->cellHeight;
|
||||
column *= font->cellWidth;
|
||||
|
||||
imageSrc = (u8*)font + font->sheetImage;
|
||||
imageSrc += ((sheet * font->sheetSize) >> 1);
|
||||
|
||||
for (y = 4; y < 8; y++) {
|
||||
x = 0;
|
||||
src = imageSrc + ((((font->sheetWidth / 8) << 5) / 2) * ((row + y) / 8));
|
||||
src += ((column + x) / 8) * 0x10;
|
||||
src += ((row + y) % 8) * 2;
|
||||
src += ((column + x) % 8) / 4;
|
||||
|
||||
*(u16*)src = imageT[y - 4];
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
u32 OSLoadFont(OSFontHeader* fontData, void* tmp) {
|
||||
u16 encode;
|
||||
u32 size;
|
||||
|
||||
encode = OSGetFontEncode();
|
||||
switch (encode) {
|
||||
case 0:
|
||||
FontDataAnsi = fontData;
|
||||
size = ReadFont(tmp, 0, FontDataAnsi);
|
||||
break;
|
||||
case 1:
|
||||
FontDataSjis = fontData;
|
||||
size = ReadFont(tmp, 1, FontDataSjis);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
FontDataAnsi = fontData;
|
||||
size = ReadFont(tmp, 0, FontDataAnsi);
|
||||
if (size != 0) {
|
||||
FontDataSjis = (OSFontHeader*)((u8*)FontDataAnsi + size);
|
||||
size += ReadFont(tmp, 1, FontDataSjis);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static char* ParseStringS(u16 encode, const char* string, OSFontHeader** pfont, int* pfontCode) {
|
||||
OSFontHeader* font;
|
||||
u16 code = 0;
|
||||
|
||||
switch (encode) {
|
||||
case OS_FONT_ENCODE_ANSI:
|
||||
font = FontDataAnsi;
|
||||
code = (u8)*string;
|
||||
if (code != 0) {
|
||||
string++;
|
||||
}
|
||||
break;
|
||||
case OS_FONT_ENCODE_SJIS:
|
||||
font = FontDataSjis;
|
||||
code = (u8)*string;
|
||||
if (code == 0) {
|
||||
break;
|
||||
}
|
||||
string++;
|
||||
|
||||
if (IsSjisLeadByte(code) && IsSjisTrailByte(*string)) {
|
||||
code = (code << 8 | (u8)*string++);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*pfont = font;
|
||||
*pfontCode = GetFontCode(encode, code);
|
||||
|
||||
return (char*)string;
|
||||
}
|
||||
|
||||
static char* ParseStringW(u16 encode, const char* string, OSFontHeader** pfont, int* pfontCode) {
|
||||
OSFontHeader* font;
|
||||
u16 code = 0;
|
||||
u32 utf32 = 0;
|
||||
|
||||
switch (encode) {
|
||||
case OS_FONT_ENCODE_ANSI:
|
||||
font = FontDataAnsi;
|
||||
code = (u8)*string;
|
||||
if (code != 0) {
|
||||
string++;
|
||||
}
|
||||
break;
|
||||
case OS_FONT_ENCODE_SJIS:
|
||||
font = FontDataSjis;
|
||||
code = (u8)*string;
|
||||
if (code == 0) {
|
||||
break;
|
||||
}
|
||||
string++;
|
||||
|
||||
if (IsSjisLeadByte(code) && IsSjisTrailByte(*string)) {
|
||||
code = (code << 8 | (u8)*string++);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
string = OSUTF8to32(string, &utf32);
|
||||
break;
|
||||
case 4:
|
||||
string = (const char*)OSUTF16to32((u16*)string, &utf32);
|
||||
break;
|
||||
case 5:
|
||||
utf32 = *(u32*)string;
|
||||
if (utf32 != 0) {
|
||||
string += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (utf32 != 0) {
|
||||
encode = 0;
|
||||
font = FontDataAnsi;
|
||||
code = OSUTF32toANSI(utf32);
|
||||
|
||||
if (code == 0 || (FixedPitch != 0 && utf32 <= 0x7F)) {
|
||||
code = OSUTF32toSJIS(utf32);
|
||||
if (code != 0) {
|
||||
encode = 1;
|
||||
font = FontDataSjis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*pfont = font;
|
||||
*pfontCode = GetFontCode(encode, code);
|
||||
|
||||
return (char*)string;
|
||||
}
|
||||
|
||||
char* OSGetFontTexel(const char* string, void* image, s32 pos, s32 stride, s32* width) {
|
||||
u16 encode;
|
||||
OSFontHeader* font;
|
||||
u8* src;
|
||||
u8* dst;
|
||||
int fontCode;
|
||||
int sheet;
|
||||
int numChars;
|
||||
int row;
|
||||
int column;
|
||||
int x;
|
||||
int y;
|
||||
int offsetSrc;
|
||||
int offsetDst;
|
||||
u8* colorIndex;
|
||||
u8* imageSrc;
|
||||
|
||||
encode = OSGetFontEncode();
|
||||
string = ParseString(encode, (char*)string, &font, &fontCode);
|
||||
colorIndex = &font->c0;
|
||||
ASSERTLINE(927, font->sheetFormat == GX_TF_I4);
|
||||
|
||||
sheet = fontCode / (font->sheetColumn * font->sheetRow);
|
||||
numChars = fontCode - (sheet * (font->sheetColumn * font->sheetRow));
|
||||
row = numChars / font->sheetColumn;
|
||||
column = numChars - (row * font->sheetColumn);
|
||||
row *= font->cellHeight;
|
||||
column *= font->cellWidth;
|
||||
|
||||
imageSrc = (u8*)font + font->sheetImage;
|
||||
imageSrc += ((sheet * font->sheetSize) >> 1);
|
||||
|
||||
for (y = 0; y < font->cellHeight; y++) {
|
||||
for (x = 0; x < font->cellWidth; x++) {
|
||||
src = imageSrc + (((font->sheetWidth / 8) * 32) / 2) * ((row + y) / 8);
|
||||
src += ((column + x) / 8) * 16;
|
||||
src += ((row + y) % 8) * 2;
|
||||
src += ((column + x) % 8) / 4;
|
||||
|
||||
offsetSrc = (column + x) % 4;
|
||||
|
||||
dst = (u8*)image + ((y / 8) * (((stride * 4) / 8) * 32));
|
||||
dst += (((pos + x) / 8) * 32);
|
||||
dst += ((y % 8) * 4);
|
||||
dst += ((pos + x) % 8) / 2;
|
||||
|
||||
offsetDst = (pos + x) % 2;
|
||||
|
||||
*dst |= (u8)(colorIndex[*src >> (6 - (offsetSrc * 2)) & 3] & ((offsetDst != 0) ? 0x0F : 0xF0));
|
||||
}
|
||||
}
|
||||
|
||||
if (width != 0) {
|
||||
*width = ((u8*)font + font->widthTable)[fontCode];
|
||||
}
|
||||
|
||||
return (char*)string;
|
||||
}
|
||||
|
||||
static void ExpandFontSheet(OSFontHeader* font, u8* src, u8* dst) {
|
||||
int i;
|
||||
u8* colorIndex = &font->c0;
|
||||
|
||||
if (font->sheetFormat == GX_TF_I4) {
|
||||
for (i = (s32)(font->sheetFullSize) / 2 - 1; i >= 0; i--) {
|
||||
dst[i * 2 + 0] =
|
||||
colorIndex[src[i] >> 6 & 3] & 0xF0 | colorIndex[src[i] >> 4 & 3] & 0x0F;
|
||||
dst[i * 2 + 1] =
|
||||
colorIndex[src[i] >> 2 & 3] & 0xF0 | colorIndex[src[i] >> 0 & 3] & 0x0F;
|
||||
}
|
||||
} else if (font->sheetFormat == GX_TF_IA4) {
|
||||
for (i = (s32)(font->sheetFullSize) / 4 - 1; i >= 0; i--) {
|
||||
dst[i * 4 + 0] = colorIndex[src[i] >> 6 & 3];
|
||||
dst[i * 4 + 1] = colorIndex[src[i] >> 4 & 3];
|
||||
dst[i * 4 + 2] = colorIndex[src[i] >> 2 & 3];
|
||||
dst[i * 4 + 3] = colorIndex[src[i] >> 0 & 3];
|
||||
}
|
||||
}
|
||||
|
||||
DCStoreRange(dst, font->sheetFullSize);
|
||||
}
|
||||
|
||||
int OSInitFont(OSFontHeader* fontData) {
|
||||
u16 encode;
|
||||
u32 size;
|
||||
void* tmp;
|
||||
u8* img;
|
||||
|
||||
ASSERTLINE(919, (u32) fontData % 32 == 0);
|
||||
|
||||
encode = OSGetFontEncode();
|
||||
switch (encode) {
|
||||
case 0:
|
||||
tmp = (void*)((u8*)fontData + 0x1D120);
|
||||
FontDataAnsi = fontData;
|
||||
size = ReadFont(tmp, 0, FontDataAnsi);
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
img = (u8*)FontDataAnsi + FontDataAnsi->sheetImage;
|
||||
FontDataAnsi->sheetImage = OSRoundUp32B(FontDataAnsi->sheetImage);
|
||||
ExpandFontSheet(FontDataAnsi, img, (u8*)FontDataAnsi + FontDataAnsi->sheetImage);
|
||||
break;
|
||||
case 1:
|
||||
tmp = (void*)((u8*)fontData + 0xD3F00);
|
||||
FontDataSjis = fontData;
|
||||
size = ReadFont(tmp, 1, FontDataSjis);
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
img = (u8*)FontDataSjis + FontDataSjis->sheetImage;
|
||||
FontDataSjis->sheetImage = OSRoundUp32B(FontDataSjis->sheetImage);
|
||||
ExpandFontSheet(FontDataSjis, img, (u8*)FontDataSjis + FontDataSjis->sheetImage);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
tmp = (void*)((u8*)fontData + 0xF4020);
|
||||
FontDataAnsi = fontData;
|
||||
size = ReadFont(tmp, 0, FontDataAnsi);
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
img = (u8*)FontDataAnsi + FontDataAnsi->sheetImage;
|
||||
FontDataAnsi->sheetImage = OSRoundUp32B(FontDataAnsi->sheetImage);
|
||||
ExpandFontSheet(FontDataAnsi, img, (u8*)FontDataAnsi + FontDataAnsi->sheetImage);
|
||||
|
||||
FontDataSjis = (OSFontHeader*)((u8*)FontDataAnsi + 0x20120);
|
||||
size = ReadFont(tmp, 1, FontDataSjis);
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
img = (u8*)FontDataSjis + FontDataSjis->sheetImage;
|
||||
FontDataSjis->sheetImage = OSRoundUp32B(FontDataSjis->sheetImage);
|
||||
ExpandFontSheet(FontDataSjis, img, (u8*)FontDataSjis + FontDataSjis->sheetImage);
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* OSGetFontTexture(const char* string, void** image, s32* x, s32* y, s32* width) {
|
||||
OSFontHeader* font;
|
||||
u16 encode;
|
||||
int fontCode;
|
||||
int sheet;
|
||||
int numChars;
|
||||
int row;
|
||||
int column;
|
||||
|
||||
encode = OSGetFontEncode();
|
||||
string = ParseString(encode, (char*)string, &font, &fontCode);
|
||||
sheet = fontCode / (font->sheetColumn * font->sheetRow);
|
||||
((u32*)image)[0] = (u32)font + font->sheetImage + (font->sheetSize * sheet);
|
||||
numChars = fontCode - (sheet * (font->sheetColumn * font->sheetRow));
|
||||
row = numChars / font->sheetColumn;
|
||||
column = numChars - (row * font->sheetColumn);
|
||||
*x = column * font->cellWidth;
|
||||
*y = row * font->cellHeight;
|
||||
|
||||
ASSERTLINE(1016, (u32) *image % 32 == 0);
|
||||
|
||||
if (width != 0) {
|
||||
*width = ((u8*)font + font->widthTable)[fontCode];
|
||||
}
|
||||
return (char*)string;
|
||||
}
|
||||
|
||||
char* OSGetFontWidth(const char* string, s32* width) {
|
||||
OSFontHeader* font;
|
||||
u16 encode;
|
||||
int fontCode;
|
||||
|
||||
encode = OSGetFontEncode();
|
||||
string = ParseString(encode, (char*)string, &font, &fontCode);
|
||||
|
||||
if (width != 0) {
|
||||
*width = ((u8*)font + font->widthTable)[fontCode];
|
||||
}
|
||||
|
||||
return (char*)string;
|
||||
}
|
||||
|
||||
int OSSetFontWidth(int fixed) {
|
||||
int prev = FixedPitch;
|
||||
FixedPitch = fixed;
|
||||
return prev;
|
||||
}
|
||||
|
|
@ -0,0 +1,519 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
#if DEBUG
|
||||
u64 __OSSpuriousInterrupts = 0;
|
||||
#endif
|
||||
static __OSInterruptHandler* InterruptHandlerTable;
|
||||
|
||||
volatile OSTime __OSLastInterruptTime;
|
||||
volatile __OSInterrupt __OSLastInterrupt;
|
||||
volatile u32 __OSLastInterruptSrr0;
|
||||
|
||||
static OSInterruptMask InterruptPrioTable[] = {
|
||||
OS_INTERRUPTMASK_PI_ERROR,
|
||||
OS_INTERRUPTMASK_PI_DEBUG,
|
||||
OS_INTERRUPTMASK_MEM,
|
||||
OS_INTERRUPTMASK_PI_RSW,
|
||||
OS_INTERRUPTMASK_PI_VI,
|
||||
0x10,
|
||||
OS_INTERRUPTMASK_PI_PE,
|
||||
OS_INTERRUPTMASK_PI_HSP,
|
||||
OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP | OS_INTERRUPTMASK_AI |
|
||||
OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI_SI | OS_INTERRUPTMASK_PI_DI,
|
||||
OS_INTERRUPTMASK_DSP_AI,
|
||||
OS_INTERRUPTMASK_PI_CP,
|
||||
0xFFFFFFFF,
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
char* __OSInterruptNames[33] = {
|
||||
"MEM_0",
|
||||
"MEM_1",
|
||||
"MEM_2",
|
||||
"MEM_3",
|
||||
"MEM_ADDRESS",
|
||||
"DSP_AI",
|
||||
"DSP_ARAM",
|
||||
"DSP_DSP",
|
||||
"AI_AI",
|
||||
"EXI_0_EXI",
|
||||
"EXI_0_TC",
|
||||
"EXI_0_EXT",
|
||||
"EXI_1_EXI",
|
||||
"EXI_1_TC",
|
||||
"EXI_1_EXT",
|
||||
"EXI_2_EXI",
|
||||
"EXI_2_TC",
|
||||
"PI_CP",
|
||||
"PI_PE_TOKEN",
|
||||
"PI_PE_FINISH",
|
||||
"PI_SI",
|
||||
"PI_DI",
|
||||
"PI_RSW",
|
||||
"PI_ERROR",
|
||||
"PI_VI",
|
||||
"PI_DEBUG",
|
||||
"PI_HSP",
|
||||
"PI_ACR",
|
||||
"unknown",
|
||||
"unknown",
|
||||
"unknown",
|
||||
"unknown",
|
||||
"unknown",
|
||||
};
|
||||
|
||||
char* __OSPIErrors[8] = {
|
||||
"No Error",
|
||||
"Misaligned address for CPU request",
|
||||
"Incorrect transfer type (tt) from CPU",
|
||||
"Unsupported transfer size",
|
||||
"Address out of range",
|
||||
"Write to ROM address space",
|
||||
"Read from GX Fifo",
|
||||
"Reserved error code",
|
||||
};
|
||||
#endif
|
||||
|
||||
// prototypes
|
||||
static void ExternalInterruptHandler(register __OSException exception, register OSContext* context);
|
||||
extern void __RAS_OSDisableInterrupts_begin(void);
|
||||
extern void __RAS_OSDisableInterrupts_end(void);
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm BOOL OSDisableInterrupts(void) {
|
||||
nofralloc
|
||||
entry __RAS_OSDisableInterrupts_begin
|
||||
mfmsr r3
|
||||
rlwinm r4, r3, 0, 17, 15
|
||||
mtmsr r4
|
||||
entry __RAS_OSDisableInterrupts_end
|
||||
rlwinm r3, r3, 17, 31, 31
|
||||
blr
|
||||
}
|
||||
|
||||
asm BOOL OSEnableInterrupts(void) {
|
||||
nofralloc
|
||||
|
||||
mfmsr r3
|
||||
ori r4, r3, 0x8000
|
||||
mtmsr r4
|
||||
rlwinm r3, r3, 17, 31, 31
|
||||
blr
|
||||
}
|
||||
|
||||
asm BOOL OSRestoreInterrupts(register BOOL level) {
|
||||
nofralloc
|
||||
|
||||
cmpwi level, 0
|
||||
mfmsr r4
|
||||
beq _disable
|
||||
ori r5, r4, 0x8000
|
||||
b _restore
|
||||
_disable:
|
||||
rlwinm r5, r4, 0, 17, 15
|
||||
_restore:
|
||||
mtmsr r5
|
||||
rlwinm r3, r4, 17, 31, 31
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
||||
__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler) {
|
||||
__OSInterruptHandler oldHandler;
|
||||
|
||||
ASSERTMSGLINE(482, InterruptHandlerTable, "__OSSetInterruptHandler(): OSInit() must be called in advance.");
|
||||
ASSERTMSGLINE(484, interrupt < 0x20, "__OSSetInterruptHandler(): unknown interrupt.");
|
||||
|
||||
oldHandler = InterruptHandlerTable[interrupt];
|
||||
InterruptHandlerTable[interrupt] = handler;
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt) {
|
||||
ASSERTMSGLINE(504, InterruptHandlerTable, "__OSGetInterruptHandler(): OSInit() must be called in advance.");
|
||||
ASSERTMSGLINE(506, interrupt < 0x20, "__OSGetInterruptHandler(): unknown interrupt.");
|
||||
return InterruptHandlerTable[interrupt];
|
||||
}
|
||||
|
||||
void __OSInterruptInit(void) {
|
||||
InterruptHandlerTable = (void*)OSPhysicalToCached(0x3040);
|
||||
|
||||
memset(InterruptHandlerTable, 0, __OS_INTERRUPT_MAX * sizeof(__OSInterruptHandler));
|
||||
|
||||
*(OSInterruptMask*)OSPhysicalToCached(0x00C4) = 0;
|
||||
*(OSInterruptMask*)OSPhysicalToCached(0x00C8) = 0;
|
||||
*(u32*)0xCC003004 = 240;
|
||||
*(u32*)0xCD000034 = 0x40000000;
|
||||
|
||||
__OSMaskInterrupts(OS_INTERRUPTMASK_MEM | OS_INTERRUPTMASK_DSP | OS_INTERRUPTMASK_AI |
|
||||
OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI);
|
||||
|
||||
__OSSetExceptionHandler(4, ExternalInterruptHandler);
|
||||
#if DEBUG
|
||||
__PIRegs[0] = 1;
|
||||
__OSUnmaskInterrupts(0x100);
|
||||
#endif
|
||||
}
|
||||
|
||||
static u32 SetInterruptMask(OSInterruptMask mask, OSInterruptMask current) {
|
||||
u32 reg;
|
||||
|
||||
switch (__cntlzw(mask)) {
|
||||
case __OS_INTERRUPT_MEM_0:
|
||||
case __OS_INTERRUPT_MEM_1:
|
||||
case __OS_INTERRUPT_MEM_2:
|
||||
case __OS_INTERRUPT_MEM_3:
|
||||
case __OS_INTERRUPT_MEM_ADDRESS:
|
||||
reg = 0;
|
||||
if (!(current & OS_INTERRUPTMASK_MEM_0))
|
||||
reg |= 0x1;
|
||||
if (!(current & OS_INTERRUPTMASK_MEM_1))
|
||||
reg |= 0x2;
|
||||
if (!(current & OS_INTERRUPTMASK_MEM_2))
|
||||
reg |= 0x4;
|
||||
if (!(current & OS_INTERRUPTMASK_MEM_3))
|
||||
reg |= 0x8;
|
||||
if (!(current & OS_INTERRUPTMASK_MEM_ADDRESS))
|
||||
reg |= 0x10;
|
||||
__MEMRegs[0x0000000e] = (u16)reg;
|
||||
mask &= ~OS_INTERRUPTMASK_MEM;
|
||||
break;
|
||||
case __OS_INTERRUPT_DSP_AI:
|
||||
case __OS_INTERRUPT_DSP_ARAM:
|
||||
case __OS_INTERRUPT_DSP_DSP:
|
||||
reg = __DSPRegs[0x00000005];
|
||||
reg &= ~0x1F8;
|
||||
if (!(current & OS_INTERRUPTMASK_DSP_AI))
|
||||
reg |= 0x10;
|
||||
if (!(current & OS_INTERRUPTMASK_DSP_ARAM))
|
||||
reg |= 0x40;
|
||||
if (!(current & OS_INTERRUPTMASK_DSP_DSP))
|
||||
reg |= 0x100;
|
||||
__DSPRegs[0x00000005] = (u16)reg;
|
||||
mask &= ~OS_INTERRUPTMASK_DSP;
|
||||
break;
|
||||
case __OS_INTERRUPT_AI_AI:
|
||||
reg = __AIRegs[0];
|
||||
reg &= ~0x2C;
|
||||
if (!(current & OS_INTERRUPTMASK_AI_AI))
|
||||
reg |= 0x4;
|
||||
__AIRegs[0] = reg;
|
||||
mask &= ~OS_INTERRUPTMASK_AI;
|
||||
break;
|
||||
case __OS_INTERRUPT_EXI_0_EXI:
|
||||
case __OS_INTERRUPT_EXI_0_TC:
|
||||
case __OS_INTERRUPT_EXI_0_EXT:
|
||||
reg = __EXIRegs[0];
|
||||
reg &= ~0x2C0F;
|
||||
if (!(current & OS_INTERRUPTMASK_EXI_0_EXI))
|
||||
reg |= 0x1;
|
||||
if (!(current & OS_INTERRUPTMASK_EXI_0_TC))
|
||||
reg |= 0x4;
|
||||
if (!(current & OS_INTERRUPTMASK_EXI_0_EXT))
|
||||
reg |= 0x400;
|
||||
__EXIRegs[0] = reg;
|
||||
mask &= ~OS_INTERRUPTMASK_EXI_0;
|
||||
break;
|
||||
case __OS_INTERRUPT_EXI_1_EXI:
|
||||
case __OS_INTERRUPT_EXI_1_TC:
|
||||
case __OS_INTERRUPT_EXI_1_EXT:
|
||||
reg = __EXIRegs[5];
|
||||
reg &= ~0xC0F;
|
||||
|
||||
if (!(current & OS_INTERRUPTMASK_EXI_1_EXI))
|
||||
reg |= 0x1;
|
||||
if (!(current & OS_INTERRUPTMASK_EXI_1_TC))
|
||||
reg |= 0x4;
|
||||
if (!(current & OS_INTERRUPTMASK_EXI_1_EXT))
|
||||
reg |= 0x400;
|
||||
__EXIRegs[5] = reg;
|
||||
mask &= ~OS_INTERRUPTMASK_EXI_1;
|
||||
break;
|
||||
case __OS_INTERRUPT_EXI_2_EXI:
|
||||
case __OS_INTERRUPT_EXI_2_TC:
|
||||
reg = __EXIRegs[10];
|
||||
reg &= ~0xF;
|
||||
if (!(current & OS_INTERRUPTMASK_EXI_2_EXI))
|
||||
reg |= 0x1;
|
||||
if (!(current & OS_INTERRUPTMASK_EXI_2_TC))
|
||||
reg |= 0x4;
|
||||
|
||||
__EXIRegs[10] = reg;
|
||||
mask &= ~OS_INTERRUPTMASK_EXI_2;
|
||||
break;
|
||||
case __OS_INTERRUPT_PI_CP:
|
||||
case __OS_INTERRUPT_PI_SI:
|
||||
case __OS_INTERRUPT_PI_DI:
|
||||
case __OS_INTERRUPT_PI_RSW:
|
||||
case __OS_INTERRUPT_PI_ERROR:
|
||||
case __OS_INTERRUPT_PI_VI:
|
||||
case __OS_INTERRUPT_PI_DEBUG:
|
||||
case __OS_INTERRUPT_PI_PE_TOKEN:
|
||||
case __OS_INTERRUPT_PI_PE_FINISH:
|
||||
case __OS_INTERRUPT_PI_HSP:
|
||||
case __OS_INTERRUPT_PI_ACR:
|
||||
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;
|
||||
}
|
||||
if (!(current & OS_INTERRUPTMASK_PI_ACR)) {
|
||||
reg |= 0x4000;
|
||||
}
|
||||
|
||||
__PIRegs[1] = reg;
|
||||
mask &= ~OS_INTERRUPTMASK_PI;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
OSInterruptMask OSGetInterruptMask(void) {
|
||||
return *(OSInterruptMask *)OSPhysicalToCached(0x00C8);
|
||||
}
|
||||
|
||||
OSInterruptMask OSSetInterruptMask(OSInterruptMask local) {
|
||||
BOOL enabled;
|
||||
OSInterruptMask global;
|
||||
OSInterruptMask prev;
|
||||
OSInterruptMask mask;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
global = *(OSInterruptMask *)OSPhysicalToCached(0x00C4);
|
||||
prev = *(OSInterruptMask *)OSPhysicalToCached(0x00C8);
|
||||
mask = (global | prev) ^ local;
|
||||
*(OSInterruptMask *)OSPhysicalToCached(0x00C8) = local;
|
||||
while (mask) {
|
||||
mask = SetInterruptMask(mask, global | local);
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return prev;
|
||||
}
|
||||
|
||||
OSInterruptMask __OSMaskInterrupts(OSInterruptMask global) {
|
||||
BOOL enabled;
|
||||
OSInterruptMask prev;
|
||||
OSInterruptMask local;
|
||||
OSInterruptMask mask;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
prev = *(OSInterruptMask *)OSPhysicalToCached(0x00C4);
|
||||
local = *(OSInterruptMask *)OSPhysicalToCached(0x00C8);
|
||||
mask = ~(prev | local) & global;
|
||||
global |= prev;
|
||||
*(OSInterruptMask *)OSPhysicalToCached(0x00C4) = global;
|
||||
while (mask) {
|
||||
mask = SetInterruptMask(mask, global | local);
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return prev;
|
||||
}
|
||||
|
||||
OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask global) {
|
||||
BOOL enabled;
|
||||
OSInterruptMask prev;
|
||||
OSInterruptMask local;
|
||||
OSInterruptMask mask;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
prev = *(OSInterruptMask *)OSPhysicalToCached(0x00C4);
|
||||
local = *(OSInterruptMask *)OSPhysicalToCached(0x00C8);
|
||||
mask = (prev | local) & global;
|
||||
global = prev & ~global;
|
||||
*(OSInterruptMask *)OSPhysicalToCached(0x00C4) = global;
|
||||
while (mask) {
|
||||
mask = SetInterruptMask(mask, global | local);
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return prev;
|
||||
}
|
||||
|
||||
void __OSDispatchInterrupt(__OSException exception, OSContext* context) {
|
||||
u32 intsr;
|
||||
u32 mask;
|
||||
u32 reg;
|
||||
OSInterruptMask cause;
|
||||
OSInterruptMask unmasked;
|
||||
OSInterruptMask* prio;
|
||||
__OSInterrupt interrupt;
|
||||
__OSInterruptHandler handler;
|
||||
|
||||
intsr = __PIRegs[0];
|
||||
intsr &= ~0x00010000;
|
||||
mask = __PIRegs[1];
|
||||
|
||||
if (intsr == 0 || (intsr & mask) == 0) {
|
||||
#if DEBUG
|
||||
__OSSpuriousInterrupts++;
|
||||
#endif
|
||||
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;
|
||||
if (intsr & 0x4000)
|
||||
cause |= OS_INTERRUPTMASK_PI_ACR;
|
||||
|
||||
#if DEBUG
|
||||
if (cause & OS_INTERRUPTMASK_PI_ERROR) {
|
||||
OSReport("PI ERROR\n");
|
||||
OSDumpContext(context);
|
||||
OSReport("\nPIESR = 0x%08x PIEAR = 0x%08x\n", __PIRegs[7], __PIRegs[8]);
|
||||
__PIRegs[0] = 1;
|
||||
OSReport("PI Error = %s\n", __OSPIErrors[__PIRegs[7]]);
|
||||
OSReport("Offending address = 0x%x (from PIEAR)\n", __PIRegs[8]);
|
||||
}
|
||||
#endif
|
||||
|
||||
unmasked = cause & ~(*(OSInterruptMask *)OSPhysicalToCached(0x00C4) |
|
||||
*(OSInterruptMask *)OSPhysicalToCached(0x00C8));
|
||||
if (unmasked) {
|
||||
for (prio = InterruptPrioTable;; ++prio) {
|
||||
if (unmasked & *prio) {
|
||||
interrupt = (__OSInterrupt)__cntlzw(unmasked & *prio);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handler = __OSGetInterruptHandler(interrupt);
|
||||
if (handler) {
|
||||
if (__OS_INTERRUPT_MEM_ADDRESS < interrupt) {
|
||||
__OSLastInterrupt = interrupt;
|
||||
__OSLastInterruptTime = OSGetTime();
|
||||
__OSLastInterruptSrr0 = context->srr0;
|
||||
}
|
||||
OSDisableScheduler();
|
||||
handler(interrupt, context);
|
||||
OSEnableScheduler();
|
||||
__OSReschedule();
|
||||
OSLoadContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
OSReport("Unhandled Interrupt(s): cause %08x intsr %08x\n", cause, intsr);
|
||||
while (cause) {
|
||||
interrupt = __cntlzw(cause);
|
||||
cause &= ~(1 << (0x1F - __cntlzw(cause)));
|
||||
OSReport(" %s\n", __OSInterruptNames[interrupt]);
|
||||
}
|
||||
#endif
|
||||
|
||||
OSLoadContext(context);
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void ExternalInterruptHandler(register __OSException exception,
|
||||
register OSContext* context) {
|
||||
#pragma unused(exception)
|
||||
nofralloc
|
||||
OS_EXCEPTION_SAVE_GPRS(context)
|
||||
|
||||
stwu r1, -0x8(r1)
|
||||
b __OSDispatchInterrupt
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#include <revolution/os/OSIpc.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
static void* IpcBufferHi;
|
||||
static void* IpcBufferLo = (void*)0xFFFFFFFF;
|
||||
|
||||
void* __OSGetIPCBufferHi(void) {
|
||||
return IpcBufferHi;
|
||||
}
|
||||
|
||||
void* __OSGetIPCBufferLo(void) {
|
||||
return IpcBufferLo;
|
||||
}
|
||||
|
||||
void __OSInitIPCBuffer(void) {
|
||||
IpcBufferLo = (void*)*(u32*)OSPhysicalToCached(0x3100 + 0x0030);
|
||||
IpcBufferHi = (void*)*(u32*)OSPhysicalToCached(0x3100 + 0x0034);
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
void __OSRelaunchTitle(u32 resetCode) {
|
||||
s32 rc = 0;
|
||||
u32 ticketCnt = 1;
|
||||
ESTicketView* tik = NULL;
|
||||
ESTitleId titleId __attribute__ ((aligned (32)));
|
||||
__OSPlayTimeType type = OSPLAYTIME_PERMANENT;
|
||||
u32 remain = 0;
|
||||
u8* bi2 = NULL;
|
||||
OSNandbootInfo* info = NULL;
|
||||
OSStateFlags state;
|
||||
|
||||
OSSetArenaLo((void*)0x81280000);
|
||||
OSSetArenaHi((void*)0x812F0000);
|
||||
|
||||
rc = ESP_InitLib();
|
||||
if (rc != 0) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
rc = ESP_GetTitleId(&titleId);
|
||||
if (rc != 0) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
tik = (ESTicketView*)(OSAllocFromMEM1ArenaLo)(OSRoundUp32B(sizeof(ESTicketView)), 32);
|
||||
if (tik == NULL) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
memset(tik, 0, OSRoundUp32B(sizeof(ESTicketView)));
|
||||
rc = ESP_DiGetTicketView(NULL, tik);
|
||||
if (rc == -1017) {
|
||||
ESTicketView* tmp = NULL;
|
||||
rc = ESP_GetTicketViews(titleId, NULL, &ticketCnt);
|
||||
if (rc != 0) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
tmp = (ESTicketView*)OSAllocFromMEM1ArenaLo(OSRoundUp32B(ticketCnt * sizeof(ESTicketView)), 32);
|
||||
if (tmp == NULL) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
rc = ESP_GetTicketViews(titleId, tmp, &ticketCnt);
|
||||
if (rc != 0) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
memcpy(tik, tmp, sizeof(ESTicketView));
|
||||
} else if (rc != 0) {
|
||||
__OSReturnToMenuForError();
|
||||
} else {
|
||||
if (OSPlayTimeIsLimited()) {
|
||||
__OSPlayTimeType type = OSPLAYTIME_PERMANENT;
|
||||
u32 remain = 0xFFFFFFFF;
|
||||
__OSGetPlayTime(tik, &type, &remain);
|
||||
if (remain == 0) {
|
||||
__OSWriteExpiredFlag();
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bi2 = (u8*)OSAllocFromMEM1ArenaLo(0x2000, 64);
|
||||
info = (OSNandbootInfo*)((u32)bi2 + (0x2000 - sizeof(OSNandbootInfo)));
|
||||
memset(bi2, 0, 0x2000);
|
||||
info->LastTitleId = titleId;
|
||||
info->LastAppType = OSGetAppType();
|
||||
info->ReturnType = 1;
|
||||
info->ArgValue = resetCode | 0x80000000;
|
||||
|
||||
__OSCreateNandbootInfo();
|
||||
__OSWriteNandbootInfo(info);
|
||||
__OSReadStateFlags(&state);
|
||||
state.lastShutdown = 3;
|
||||
__OSWriteStateFlags(&state);
|
||||
rc = ESP_LaunchTitle(titleId, tik);
|
||||
|
||||
if (rc != 0) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,537 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
#define SHN_UNDEF 0
|
||||
#define SHN_LORESERVE 0xff00
|
||||
#define SHN_LOPROC 0xff00
|
||||
#define SHN_HIPROC 0xff1f
|
||||
#define SHN_ABS 0xfff1
|
||||
#define SHN_COMMON 0xfff2
|
||||
#define SHN_HIRESERVE 0xffff
|
||||
|
||||
#define ELF32_R_SYM(i) ((i) >> 8)
|
||||
#define ELF32_R_TYPE(i) ((unsigned char)(i))
|
||||
#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
|
||||
|
||||
// Name Value Field Calculation
|
||||
#define R_PPC_NONE 0 // none none
|
||||
#define R_PPC_ADDR32 1 // word32 S + A
|
||||
#define R_PPC_ADDR24 2 // low24* (S + A) >> 2
|
||||
#define R_PPC_ADDR16 3 // half16* S + A
|
||||
#define R_PPC_ADDR16_LO 4 // half16 #lo(S + A)
|
||||
#define R_PPC_ADDR16_HI 5 // half16 #hi(S + A)
|
||||
#define R_PPC_ADDR16_HA 6 // half16 #ha(S + A)
|
||||
#define R_PPC_ADDR14 7 // low14* (S + A) >> 2
|
||||
#define R_PPC_ADDR14_BRTAKEN 8 // low14* (S + A) >> 2
|
||||
#define R_PPC_ADDR14_BRNTAKEN 9 // low14* (S + A) >> 2
|
||||
#define R_PPC_REL24 10 // low24* (S + A - P) >> 2
|
||||
#define R_PPC_REL14 11 // low14* (S + A - P) >> 2
|
||||
#define R_PPC_REL14_BRTAKEN 12 // low14* (S + A - P) >> 2
|
||||
#define R_PPC_REL14_BRNTAKEN 13 // low14* (S + A - P) >> 2
|
||||
|
||||
#define R_PPC_GOT16 14 // half16* G + A
|
||||
#define R_PPC_GOT16_LO 15 // half16 #lo(G + A)
|
||||
#define R_PPC_GOT16_HI 16 // half16 #hi(G + A)
|
||||
#define R_PPC_GOT16_HA 17 // half16 #ha(G + A)
|
||||
#define R_PPC_PLTREL24 18 // low24* (L + A - P) >> 2
|
||||
#define R_PPC_COPY 19 // none none
|
||||
#define R_PPC_GLOB_DAT 20 // word32 S + A
|
||||
#define R_PPC_JMP_SLOT 21 // none
|
||||
#define R_PPC_RELATIVE 22 // word32 B + A
|
||||
|
||||
#define R_PPC_LOCAL24PC 23 // low24*
|
||||
|
||||
#define R_PPC_UADDR32 24 // word32 S + A
|
||||
#define R_PPC_UADDR16 25 // half16* S + A
|
||||
#define R_PPC_REL32 26 // word32 S + A - P
|
||||
|
||||
#define R_PPC_PLT32 27 // word32 L + A
|
||||
#define R_PPC_PLTREL32 28 // word32 L + A - P
|
||||
#define R_PPC_PLT16_LO 29 // half16 #lo(L + A)
|
||||
#define R_PPL_PLT16_HI 30 // half16 #hi(L + A)
|
||||
#define R_PPC_PLT16_HA 31 // half16 #ha(L + A)
|
||||
|
||||
#define R_PPC_SDAREL16 32 // half16* S + A - _SDA_BASE_
|
||||
#define R_PPC_SECTOFF 33 // half16* R + A
|
||||
#define R_PPC_SECTOFF_LO 34 // half16 #lo(R + A)
|
||||
#define R_PPC_SECTOFF_HI 35 // half16 #hi(R + A)
|
||||
#define R_PPC_SECTOFF_HA 36 // half16 #ha(R + A)
|
||||
#define R_PPC_ADDR30 37 // word30 (S + A - P) >> 2
|
||||
|
||||
#define R_PPC_EMB_NADDR32 101 // uword32 N (A - S)
|
||||
#define R_PPC_EMB_NADDR16 102 // uhalf16 Y (A - S)
|
||||
#define R_PPC_EMB_NADDR16_LO 103 // uhalf16 N #lo(A - S)
|
||||
#define R_PPC_EMB_NADDR16_HI 104 // uhalf16 N #hi(A - S)
|
||||
#define R_PPC_EMB_NADDR16_HA 105 // uhalf16 N #ha(A - S)
|
||||
#define R_PPC_EMB_SDAI16 106 // uhalf16 Y T
|
||||
#define R_PPC_EMB_SDA2I16 107 // uhalf16 Y U
|
||||
#define R_PPC_EMB_SDA2REL 108 // uhalf16 Y S + A - _SDA2_BASE_
|
||||
#define R_PPC_EMB_SDA21 109 // ulow21 N
|
||||
#define R_PPC_EMB_MRKREF 110 // none N
|
||||
#define R_PPC_EMB_RELSEC16 111 // uhalf16 Y V + A
|
||||
#define R_PPC_EMB_RELST_LO 112 // uhalf16 N #lo(W + A)
|
||||
#define R_PPC_EMB_RELST_HI 113 // uhalf16 N #hi(W + A)
|
||||
#define R_PPC_EMB_RELST_HA 114 // uhalf16 N #ha(W + A)
|
||||
#define R_PPC_EMB_BIT_FLD 115 // uword32 Y
|
||||
#define R_PPC_EMB_RELSDA 116 // uhalf16 Y
|
||||
|
||||
OSModuleQueue __OSModuleInfoList AT_ADDRESS(OS_BASE_CACHED | 0x30C8);
|
||||
const void* __OSStringTable AT_ADDRESS(OS_BASE_CACHED | 0x30D0);
|
||||
|
||||
#define ENQUEUE_INFO(queue, info, link) \
|
||||
do { \
|
||||
OSModuleInfo* __prev; \
|
||||
\
|
||||
__prev = (queue)->tail; \
|
||||
if (__prev == NULL) \
|
||||
(queue)->head = (info); \
|
||||
else \
|
||||
__prev->link.next = (info); \
|
||||
(info)->link.prev = __prev; \
|
||||
(info)->link.next = NULL; \
|
||||
(queue)->tail = (info); \
|
||||
} while (0)
|
||||
|
||||
#define DEQUEUE_INFO(info, queue, link) \
|
||||
do { \
|
||||
OSModuleInfo* __next; \
|
||||
OSModuleInfo* __prev; \
|
||||
\
|
||||
__next = (info)->link.next; \
|
||||
__prev = (info)->link.prev; \
|
||||
\
|
||||
if (__next == NULL) \
|
||||
(queue)->tail = __prev; \
|
||||
else \
|
||||
__next->link.prev = __prev; \
|
||||
\
|
||||
if (__prev == NULL) \
|
||||
(queue)->head = __next; \
|
||||
else \
|
||||
__prev->link.next = __next; \
|
||||
} while (0)
|
||||
|
||||
#pragma dont_inline on
|
||||
void OSNotifyLink(OSModuleInfo* module) {}
|
||||
|
||||
void OSNotifyUnlink(OSModuleInfo* module) {}
|
||||
|
||||
void OSNotifyPreLink(OSModuleHeader* newModule, OSModuleHeader* module) {}
|
||||
|
||||
void OSNotifyPostLink(OSModuleHeader* newModule, OSModuleHeader* module) {}
|
||||
#pragma dont_inline reset
|
||||
|
||||
void OSSetStringTable(void* stringTable) {
|
||||
__OSStringTable = stringTable;
|
||||
}
|
||||
|
||||
static BOOL Relocate(OSModuleHeader* newModule, OSModuleHeader* module) {
|
||||
OSModuleID idNew;
|
||||
OSImportInfo* imp;
|
||||
OSRel* rel;
|
||||
OSSectionInfo* si;
|
||||
OSSectionInfo* siFlush;
|
||||
u32* p;
|
||||
u32 offset;
|
||||
u32 x;
|
||||
|
||||
idNew = newModule ? newModule->info.id : 0;
|
||||
for (imp = (OSImportInfo*)module->impOffset;
|
||||
imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++)
|
||||
{
|
||||
if (imp->id == idNew) {
|
||||
goto Found;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
Found:
|
||||
OSNotifyPreLink(newModule, module);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
OSNotifyPostLink(newModule, module);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL Link(OSModuleInfo* newModule, void* bss, BOOL fixed) {
|
||||
u32 i;
|
||||
OSSectionInfo* si;
|
||||
OSModuleHeader* moduleHeader;
|
||||
OSModuleInfo* moduleInfo;
|
||||
OSImportInfo* imp;
|
||||
|
||||
ASSERTLINE(313, newModule->version <= OS_MODULE_VERSION);
|
||||
|
||||
moduleHeader = (OSModuleHeader*)newModule;
|
||||
moduleHeader->bssSection = 0;
|
||||
|
||||
ASSERTLINE(321, newModule->version < 2 || moduleHeader->align == 0 || (u32) newModule % moduleHeader->align == 0);
|
||||
ASSERTLINE(324, newModule->version < 2 || moduleHeader->bssAlign == 0 || (u32) bss % moduleHeader->bssAlign == 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;
|
||||
}
|
||||
|
||||
ENQUEUE_INFO(&__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) {
|
||||
ASSERTLINE(357, moduleHeader->bssSection == 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) {
|
||||
ASSERTLINE(431, newModule->version <= OS_MODULE_VERSION && 3 <= newModule->version);
|
||||
|
||||
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;
|
||||
|
||||
ASSERTLINE(465, newModule);
|
||||
|
||||
idNew = newModule->info.id;
|
||||
ASSERTLINE(467, idNew);
|
||||
|
||||
for (imp = (OSImportInfo*)module->impOffset;
|
||||
imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++)
|
||||
{
|
||||
if (imp->id == idNew) {
|
||||
goto Found;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
Found:
|
||||
OSNotifyPreLink(newModule, module);
|
||||
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);
|
||||
}
|
||||
|
||||
OSNotifyPostLink(newModule, module);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL OSUnlink(OSModuleInfo* oldModule) {
|
||||
OSModuleHeader* moduleHeader;
|
||||
OSModuleInfo* moduleInfo;
|
||||
u32 i;
|
||||
OSSectionInfo* si;
|
||||
OSImportInfo* imp;
|
||||
|
||||
ASSERTLINE(584, oldModule->version <= OS_MODULE_VERSION);
|
||||
|
||||
moduleHeader = (OSModuleHeader*)oldModule;
|
||||
|
||||
DEQUEUE_INFO(oldModule, &__OSModuleInfoList, 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) {
|
||||
ASSERTLINE(627, si->size != 0);
|
||||
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) {
|
||||
__OSModuleInfoList.head = __OSModuleInfoList.tail = 0;
|
||||
__OSStringTable = 0;
|
||||
}
|
||||
|
||||
OSModuleInfo* OSSearchModule(void* ptr, u32* section, u32* offset) {
|
||||
OSModuleInfo* moduleInfo;
|
||||
OSSectionInfo* sectionInfo;
|
||||
u32 i;
|
||||
u32 baseSection;
|
||||
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
moduleInfo = __OSModuleInfoList.head;
|
||||
while (moduleInfo != 0) {
|
||||
sectionInfo = (OSSectionInfo*)moduleInfo->sectionInfoOffset;
|
||||
for (i = 0; i < moduleInfo->numSections; i++) {
|
||||
if (sectionInfo->size != 0) {
|
||||
baseSection = sectionInfo->offset & 0xFFFFFFFE;
|
||||
if (baseSection <= (u32)ptr && (u32)ptr < baseSection + sectionInfo->size) {
|
||||
if (section != 0) {
|
||||
*section = i;
|
||||
}
|
||||
|
||||
if (offset != 0) {
|
||||
*offset = (u32)ptr - baseSection;
|
||||
}
|
||||
|
||||
return moduleInfo;
|
||||
}
|
||||
}
|
||||
sectionInfo++;
|
||||
}
|
||||
moduleInfo = moduleInfo->link.next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,680 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/dvd.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
#define TRUNC(n, a) (((u32)(n)) & ~((a)-1))
|
||||
#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1))
|
||||
|
||||
static BOOL OnShutdown(BOOL final, u32 event);
|
||||
|
||||
static OSShutdownFunctionInfo ShutdownFunctionInfo = {
|
||||
OnShutdown,
|
||||
0x7F,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
u32 OSGetPhysicalMem1Size(void) {
|
||||
u32 memSize = *(u32*)OSPhysicalToCached(0x3100);
|
||||
return memSize;
|
||||
}
|
||||
|
||||
u32 OSGetPhysicalMem2Size(void) {
|
||||
u32 memSize = *(u32*)OSPhysicalToCached(0x3118);
|
||||
return memSize;
|
||||
}
|
||||
|
||||
u32 OSGetConsoleSimulatedMem1Size(void) {
|
||||
u32 memSize = *(u32*)OSPhysicalToCached(0x3104);
|
||||
return memSize;
|
||||
}
|
||||
|
||||
u32 OSGetConsoleSimulatedMem2Size(void) {
|
||||
u32 memSize = *(u32*)OSPhysicalToCached(0x311C);
|
||||
return memSize;
|
||||
}
|
||||
|
||||
static BOOL OnShutdown(BOOL final, u32 event) {
|
||||
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[__OS_EXCEPTION_MEMORY_PROTECTION]) {
|
||||
__OSErrorTable[__OS_EXCEPTION_MEMORY_PROTECTION](__OS_EXCEPTION_MEMORY_PROTECTION, context, cause, addr);
|
||||
return;
|
||||
}
|
||||
|
||||
__OSUnhandledException(__OS_EXCEPTION_MEMORY_PROTECTION, context, cause, addr);
|
||||
}
|
||||
|
||||
void OSProtectRange(u32 chan, void* addr, u32 nBytes, u32 control) {
|
||||
BOOL enabled;
|
||||
u32 start;
|
||||
u32 end;
|
||||
u16 reg;
|
||||
|
||||
ASSERTLINE(388, chan < 4);
|
||||
ASSERTLINE(389, (control & ~(OS_PROTECT_CONTROL_RDWR)) == 0);
|
||||
|
||||
if (4 <= chan) {
|
||||
return;
|
||||
}
|
||||
|
||||
control &= 3;
|
||||
|
||||
end = (u32)addr + nBytes;
|
||||
start = TRUNC(addr, 1u << 10);
|
||||
end = ROUND(end, 1u << 10);
|
||||
|
||||
DCFlushRange((void*)start, end - start);
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
__OSMaskInterrupts(OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0 + chan));
|
||||
|
||||
__MEMRegs[0 + 2 * chan] = (u16)(start >> 10);
|
||||
__MEMRegs[1 + 2 * chan] = (u16)(end >> 10);
|
||||
|
||||
reg = __MEMRegs[8];
|
||||
reg &= ~(3 << 2 * chan);
|
||||
reg |= control << 2 * chan;
|
||||
__MEMRegs[8] = reg;
|
||||
|
||||
if (control != 3) {
|
||||
__OSUnmaskInterrupts(OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0 + chan));
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void ConfigMEM1_24MB(void) {
|
||||
nofralloc
|
||||
addi r7, r0, 0
|
||||
|
||||
addis r4,r0,0x00000002@ha
|
||||
addi r4,r4,0x00000002@l
|
||||
addis r3,r0,0x800001ff@ha
|
||||
addi r3,r3,0x800001ff@l
|
||||
|
||||
addis r6,r0,0x01000002@ha
|
||||
addi r6,r6,0x01000002@l
|
||||
addis r5,r0,0x810000ff@ha
|
||||
addi r5,r5,0x810000ff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr dbat0u,r7
|
||||
mtspr dbat0l,r4
|
||||
mtspr dbat0u,r3
|
||||
isync
|
||||
|
||||
mtspr ibat0u,r7
|
||||
mtspr ibat0l,r4
|
||||
mtspr ibat0u,r3
|
||||
isync
|
||||
|
||||
mtspr dbat2u,r7
|
||||
mtspr dbat2l,r6
|
||||
mtspr dbat2u,r5
|
||||
isync
|
||||
|
||||
mtspr ibat2u,r7
|
||||
mtspr ibat2l,r6
|
||||
mtspr ibat2u,r5
|
||||
isync
|
||||
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
mflr r3
|
||||
mtsrr0 r3
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void ConfigMEM1_48MB(void) {
|
||||
nofralloc
|
||||
|
||||
addi r7,r0, 0
|
||||
|
||||
addis r4,r0,0x00000002@ha
|
||||
addi r4,r4,0x00000002@l
|
||||
addis r3,r0,0x800003ff@ha
|
||||
addi r3,r3,0x800003ff@l
|
||||
|
||||
addis r6,r0,0x02000002@ha
|
||||
addi r6,r6,0x02000002@l
|
||||
addis r5,r0,0x820001ff@ha
|
||||
addi r5,r5,0x820001ff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr dbat0u,r7
|
||||
mtspr dbat0l,r4
|
||||
mtspr dbat0u,r3
|
||||
isync
|
||||
|
||||
mtspr ibat0u,r7
|
||||
mtspr ibat0l,r4
|
||||
mtspr ibat0u,r3
|
||||
isync
|
||||
|
||||
mtspr dbat2u,r7
|
||||
mtspr dbat2l,r6
|
||||
mtspr dbat2u,r5
|
||||
isync
|
||||
|
||||
mtspr ibat2u,r7
|
||||
mtspr ibat2l,r6
|
||||
mtspr ibat2u,r5
|
||||
isync
|
||||
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
mflr r3
|
||||
mtsrr0 r3
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void ConfigMEM2_52MB(void) {
|
||||
nofralloc
|
||||
|
||||
addi r7, r0, 0
|
||||
|
||||
addis r4,r0,0x10000002@ha
|
||||
addi r4,r4,0x10000002@l
|
||||
addis r3,r0,0x900003ff@ha
|
||||
addi r3,r3,0x900003ff@l
|
||||
|
||||
addis r6,r0,0x1000002a@ha
|
||||
addi r6,r6,0x1000002a@l
|
||||
addis r5,r0,0xD00007ff@ha
|
||||
addi r5,r5,0xD00007ff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT4U,r7
|
||||
mtspr DBAT4L,r4
|
||||
mtspr DBAT4U,r3
|
||||
isync
|
||||
|
||||
mtspr IBAT4U,r7
|
||||
mtspr IBAT4L,r7
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT5U,r7
|
||||
mtspr DBAT5L,r6
|
||||
mtspr DBAT5U,r5
|
||||
isync
|
||||
|
||||
mtspr IBAT5U,r7
|
||||
mtspr IBAT5L,r7
|
||||
isync
|
||||
|
||||
addis r4,r0,0x12000002@ha
|
||||
addi r4,r4,0x12000002@l
|
||||
addis r3,r0,0x920001ff@ha
|
||||
addi r3,r3,0x920001ff@l
|
||||
|
||||
addis r6,r0,0x13000002@ha
|
||||
addi r6,r6,0x13000002@l
|
||||
addis r5,r0,0x9300007f@ha
|
||||
addi r5,r5,0x9300007f@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT6U,r7
|
||||
mtspr DBAT6L,r4
|
||||
mtspr DBAT6U,r3
|
||||
isync
|
||||
|
||||
mtspr IBAT6U,r7
|
||||
mtspr IBAT6L,r7
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT7U,r7
|
||||
mtspr DBAT7L,r6
|
||||
mtspr DBAT7U,r5
|
||||
isync
|
||||
|
||||
mtspr IBAT7U,r7
|
||||
mtspr IBAT7L,r7
|
||||
|
||||
isync
|
||||
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
mflr r3
|
||||
mtsrr0 r3
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void ConfigMEM2_56MB(void) {
|
||||
nofralloc
|
||||
|
||||
addi r7,r0, 0
|
||||
|
||||
addis r4,r0,0x10000002@ha
|
||||
addi r4,r4,0x10000002@l
|
||||
addis r3,r0,0x900003ff@ha
|
||||
addi r3,r3,0x900003ff@l
|
||||
|
||||
addis r6,r0,0x1000002a@ha
|
||||
addi r6,r6,0x1000002a@l
|
||||
addis r5,r0,0xD00007ff@ha
|
||||
addi r5,r5,0xD00007ff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT4U,r7
|
||||
mtspr DBAT4L,r4
|
||||
mtspr DBAT4U,r3
|
||||
isync
|
||||
|
||||
mtspr IBAT4U,r7
|
||||
mtspr IBAT4L,r7
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT5U,r7
|
||||
mtspr DBAT5L,r6
|
||||
mtspr DBAT5U,r5
|
||||
isync
|
||||
|
||||
mtspr IBAT5U,r7
|
||||
mtspr IBAT5L,r7
|
||||
isync
|
||||
|
||||
addis r4,r0,0x12000002@ha
|
||||
addi r4,r4,0x12000002@l
|
||||
addis r3,r0,0x920001ff@ha
|
||||
addi r3,r3,0x920001ff@l
|
||||
|
||||
addis r6,r0,0x13000002@ha
|
||||
addi r6,r6,0x13000002@l
|
||||
addis r5,r0,0x930000ff@ha
|
||||
addi r5,r5,0x930000ff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT6U,r7
|
||||
mtspr DBAT6L,r4
|
||||
mtspr DBAT6U,r3
|
||||
isync
|
||||
|
||||
mtspr IBAT6U,r7
|
||||
mtspr IBAT6L,r7
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT7U,r7
|
||||
mtspr DBAT7L,r6
|
||||
mtspr DBAT7U,r5
|
||||
isync
|
||||
|
||||
mtspr IBAT7U,r7
|
||||
mtspr IBAT7L,r7
|
||||
|
||||
isync
|
||||
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
mflr r3
|
||||
mtsrr0 r3
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void ConfigMEM2_64MB(void) {
|
||||
nofralloc
|
||||
|
||||
addi r7,r0,0x0000
|
||||
|
||||
addis r4,r0,0x10000002@ha
|
||||
addi r4,r4,0x10000002@l
|
||||
addis r3,r0,0x900007ff@ha
|
||||
addi r3,r3,0x900007ff@l
|
||||
|
||||
addis r6,r0,0x1000002a@ha
|
||||
addi r6,r6,0x1000002a@l
|
||||
addis r5,r0,0xD00007ff@ha
|
||||
addi r5,r5,0xD00007ff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT4U,r7
|
||||
mtspr DBAT4L,r4
|
||||
mtspr DBAT4U,r3
|
||||
isync
|
||||
|
||||
mtspr IBAT4U,r7
|
||||
mtspr IBAT4L,r7
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT5U,r7
|
||||
mtspr DBAT5L,r6
|
||||
mtspr DBAT5U,r5
|
||||
isync
|
||||
|
||||
mtspr IBAT5U,r7
|
||||
mtspr IBAT5L,r7
|
||||
isync
|
||||
|
||||
mtspr IBAT6U,r7
|
||||
mtspr IBAT6L,r7
|
||||
isync
|
||||
|
||||
mtspr IBAT7U,r7
|
||||
mtspr IBAT7L,r7
|
||||
isync
|
||||
|
||||
mtspr DBAT6U,r7
|
||||
mtspr DBAT6L,r7
|
||||
isync
|
||||
|
||||
mtspr DBAT7U,r7
|
||||
mtspr DBAT7L,r7
|
||||
isync
|
||||
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
mflr r3
|
||||
mtsrr0 r3
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void ConfigMEM2_112MB(void) {
|
||||
nofralloc
|
||||
|
||||
addi r7, r0, 0
|
||||
|
||||
addis r4,r0,0x10000002@ha
|
||||
addi r4,r4,0x10000002@l
|
||||
addis r3,r0,0x900007ff@ha
|
||||
addi r3,r3,0x900007ff@l
|
||||
|
||||
addis r6,r0,0x1000002a@ha
|
||||
addi r6,r6,0x1000002a@l
|
||||
addis r5,r0,0xD0000fff@ha
|
||||
addi r5,r5,0xD0000fff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT4U,r7
|
||||
mtspr DBAT4L,r4
|
||||
mtspr DBAT4U,r3
|
||||
isync
|
||||
|
||||
mtspr IBAT4U,r7
|
||||
mtspr IBAT4L,r7
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT5U,r7
|
||||
mtspr DBAT5L,r6
|
||||
mtspr DBAT5U,r5
|
||||
isync
|
||||
|
||||
mtspr IBAT5U,r7
|
||||
mtspr IBAT5L,r7
|
||||
isync
|
||||
|
||||
addis r4,r0,0x14000002@ha
|
||||
addi r4,r4,0x14000002@l
|
||||
addis r3,r0,0x940003ff@ha
|
||||
addi r3,r3,0x940003ff@l
|
||||
|
||||
addis r6,r0,0x16000002@ha
|
||||
addi r6,r6,0x16000002@l
|
||||
addis r5,r0,0x960001ff@ha
|
||||
addi r5,r5,0x960001ff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT6U,r7
|
||||
mtspr DBAT6L,r4
|
||||
mtspr DBAT6U,r3
|
||||
isync
|
||||
|
||||
mtspr IBAT6U,r7
|
||||
mtspr IBAT6L,r7
|
||||
isync
|
||||
|
||||
mtspr DBAT7U,r7
|
||||
mtspr DBAT7L,r6
|
||||
mtspr DBAT7U,r5
|
||||
isync
|
||||
|
||||
mtspr IBAT7U,r7
|
||||
mtspr IBAT7L,r7
|
||||
|
||||
isync
|
||||
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
mflr r3
|
||||
mtsrr0 r3
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void ConfigMEM2_128MB(void) {
|
||||
nofralloc
|
||||
|
||||
addi r7, r0, 0
|
||||
|
||||
addis r4,r0,0x10000002@ha
|
||||
addi r4,r4,0x10000002@l
|
||||
addis r3,r0,0x90000fff@ha
|
||||
addi r3,r3,0x90000fff@l
|
||||
|
||||
addis r6,r0,0x1000002a@ha
|
||||
addi r6,r6,0x1000002a@l
|
||||
addis r5,r0,0xD0000fff@ha
|
||||
addi r5,r5,0xD0000fff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT4U,r7
|
||||
mtspr DBAT4L,r4
|
||||
mtspr DBAT4U,r3
|
||||
isync
|
||||
|
||||
mtspr IBAT4U,r7
|
||||
mtspr IBAT4L,r7
|
||||
|
||||
isync
|
||||
|
||||
mtspr DBAT5U,r7
|
||||
mtspr DBAT5L,r6
|
||||
mtspr DBAT5U,r5
|
||||
isync
|
||||
|
||||
mtspr IBAT5U,r7
|
||||
mtspr IBAT5L,r7
|
||||
isync
|
||||
|
||||
mtspr IBAT6U,r7
|
||||
mtspr IBAT6L,r7
|
||||
isync
|
||||
|
||||
mtspr IBAT7U,r7
|
||||
mtspr IBAT7L,r7
|
||||
isync
|
||||
|
||||
mtspr DBAT6U,r7
|
||||
mtspr DBAT6L,r7
|
||||
isync
|
||||
|
||||
mtspr DBAT7U,r7
|
||||
mtspr DBAT7L,r7
|
||||
isync
|
||||
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
mflr r3
|
||||
mtsrr0 r3
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void ConfigMEM_ES1_0(void) {
|
||||
nofralloc
|
||||
|
||||
addi r7, r0, 0
|
||||
|
||||
addis r4,r0,0x00000002@ha
|
||||
addi r4,r4,0x00000002@l
|
||||
addis r3,r0,0x80000fff@ha
|
||||
addi r3,r3,0x80000fff@l
|
||||
|
||||
isync
|
||||
|
||||
mtspr dbat0u,r7
|
||||
mtspr dbat0l,r4
|
||||
mtspr dbat0u,r3
|
||||
isync
|
||||
|
||||
mtspr ibat0u,r7
|
||||
mtspr ibat0l,r4
|
||||
mtspr ibat0u,r3
|
||||
isync
|
||||
|
||||
mfmsr r3
|
||||
ori r3, r3, 0x30
|
||||
mtsrr1 r3
|
||||
|
||||
mflr r3
|
||||
mtsrr0 r3
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void RealMode(register u32 addr) {
|
||||
nofralloc
|
||||
clrlwi addr, addr, 2
|
||||
mtsrr0 addr
|
||||
mfmsr addr
|
||||
rlwinm addr, addr, 0, 28, 25
|
||||
mtsrr1 addr
|
||||
rfi
|
||||
}
|
||||
#endif
|
||||
|
||||
static void BATConfig(u32 param_0) {
|
||||
u32 size1, size2, prot;
|
||||
size1 = OSGetConsoleSimulatedMem1Size();
|
||||
|
||||
if (size1 < OSGetPhysicalMem1Size() && size1 == 25165824) {
|
||||
DCInvalidateRange((void*)0x81800000, 25165824);
|
||||
__MEMRegs[0x14] = 2;
|
||||
}
|
||||
|
||||
if (size1 <= 25165824) {
|
||||
RealMode((u32)ConfigMEM1_24MB);
|
||||
}
|
||||
|
||||
size2 = OSGetConsoleSimulatedMem2Size();
|
||||
prot = *(u32*)OSPhysicalToCached(0x3120);
|
||||
|
||||
if (size2 <= 67108864) {
|
||||
if (prot <= 0x93400000) {
|
||||
RealMode((u32)ConfigMEM2_52MB);
|
||||
}
|
||||
else if (prot <= 0x93800000) {
|
||||
RealMode((u32)ConfigMEM2_56MB);
|
||||
}
|
||||
else {
|
||||
RealMode((u32)ConfigMEM2_64MB);
|
||||
}
|
||||
}
|
||||
else if (size2 <= 134217728) {
|
||||
if (prot <= 0x97000000) {
|
||||
RealMode((u32)ConfigMEM2_112MB);
|
||||
}
|
||||
else {
|
||||
RealMode((u32)ConfigMEM2_128MB);
|
||||
}
|
||||
}
|
||||
|
||||
while (param_0 != 0xBA2CF) {}
|
||||
}
|
||||
|
||||
void __OSRestoreCodeExecOnMEM1(u32 param_0) {
|
||||
RealMode((u32)ConfigMEM1_24MB);
|
||||
while (param_0 != 0xBA2CF) {}
|
||||
}
|
||||
|
||||
void __OSInitMemoryProtection(void) {
|
||||
static BOOL initialized = FALSE;
|
||||
#ifndef DEBUG
|
||||
u32 padding[9];
|
||||
u32 temp;
|
||||
#endif
|
||||
BOOL enabled;
|
||||
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
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_INTERRUPT_MEM_0, MEMIntrruptHandler);
|
||||
__OSSetInterruptHandler(__OS_INTERRUPT_MEM_1, MEMIntrruptHandler);
|
||||
__OSSetInterruptHandler(__OS_INTERRUPT_MEM_2, MEMIntrruptHandler);
|
||||
__OSSetInterruptHandler(__OS_INTERRUPT_MEM_3, MEMIntrruptHandler);
|
||||
__OSSetInterruptHandler(__OS_INTERRUPT_MEM_ADDRESS, MEMIntrruptHandler);
|
||||
OSRegisterShutdownFunction(&ShutdownFunctionInfo);
|
||||
|
||||
BATConfig(0xBA2CF);
|
||||
|
||||
__OSUnmaskInterrupts(OS_INTERRUPTMASK_MEM_ADDRESS);
|
||||
initialized = TRUE;
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
void OSInitMessageQueue(OSMessageQueue* mq, void* msgArray, s32 msgCount) {
|
||||
OSInitThreadQueue(&mq->queueSend);
|
||||
OSInitThreadQueue(&mq->queueReceive);
|
||||
mq->msgArray = msgArray;
|
||||
mq->msgCount = msgCount;
|
||||
mq->firstIndex = 0;
|
||||
mq->usedCount = 0;
|
||||
}
|
||||
|
||||
int OSSendMessage(OSMessageQueue* mq, void* msg, s32 flags) {
|
||||
BOOL enabled;
|
||||
s32 lastIndex;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
while(mq->msgCount <= mq->usedCount) {
|
||||
if (!(flags & 1)) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
OSSleepThread(&mq->queueSend);
|
||||
}
|
||||
lastIndex = (mq->firstIndex + mq->usedCount) % mq->msgCount;
|
||||
((u32*)mq->msgArray)[lastIndex] = (u32)msg;
|
||||
mq->usedCount++;
|
||||
OSWakeupThread(&mq->queueReceive);
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSReceiveMessage(OSMessageQueue* mq, void* msg, s32 flags) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
while(mq->usedCount == 0) {
|
||||
if (!(flags & 1)) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
OSSleepThread(&mq->queueReceive);
|
||||
}
|
||||
if(msg != NULL) {
|
||||
*(u32*)msg = ((u32*)mq->msgArray)[mq->firstIndex];
|
||||
}
|
||||
|
||||
mq->firstIndex = (mq->firstIndex + 1) % mq->msgCount;
|
||||
mq->usedCount--;
|
||||
OSWakeupThread(&mq->queueSend);
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSJamMessage(OSMessageQueue* mq, void* msg, s32 flags) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
while(mq->msgCount <= mq->usedCount) {
|
||||
if(!(flags & 1)) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
OSSleepThread(&mq->queueSend);
|
||||
}
|
||||
mq->firstIndex = (mq->firstIndex + mq->msgCount - 1) % mq->msgCount;
|
||||
((u32*)mq->msgArray)[mq->firstIndex] = (u32)msg;
|
||||
mq->usedCount++;
|
||||
OSWakeupThread(&mq->queueReceive);
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
#define ENQUEUE_MUTEX(mutex, queue, link) \
|
||||
do { \
|
||||
OSMutex* __prev = (queue)->tail; \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = (mutex); \
|
||||
} else { \
|
||||
__prev->link.next = (mutex); \
|
||||
} \
|
||||
(mutex)->link.prev = __prev; \
|
||||
(mutex)->link.next = 0; \
|
||||
(queue)->tail = (mutex); \
|
||||
} while(0);
|
||||
|
||||
#define DEQUEUE_MUTEX(mutex, queue, link) \
|
||||
do { \
|
||||
OSMutex* __next = (mutex)->link.next; \
|
||||
OSMutex* __prev = (mutex)->link.prev; \
|
||||
if (__next == NULL) { \
|
||||
(queue)->tail = __prev; \
|
||||
} else { \
|
||||
__next->link.prev = __prev; \
|
||||
} \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = __next; \
|
||||
} else { \
|
||||
__prev->link.next = __next; \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define DEQUEUE_HEAD(mutex, queue, link) \
|
||||
do { \
|
||||
OSMutex* __next = mutex->link.next; \
|
||||
if (__next == NULL) { \
|
||||
(queue)->tail = 0; \
|
||||
} else { \
|
||||
__next->link.prev = 0; \
|
||||
} \
|
||||
(queue)->head = __next; \
|
||||
} while(0);
|
||||
|
||||
// prototypes
|
||||
static int IsMember(OSMutexQueue* queue, OSMutex* mutex);
|
||||
int __OSCheckMutex(OSMutex* mutex);
|
||||
int __OSCheckDeadLock(OSThread* thread);
|
||||
int __OSCheckMutexes(OSThread* thread);
|
||||
|
||||
void OSInitMutex(OSMutex* mutex) {
|
||||
OSInitThreadQueue(&mutex->queue);
|
||||
mutex->thread = 0;
|
||||
mutex->count = 0;
|
||||
}
|
||||
|
||||
void OSLockMutex(OSMutex* mutex) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(146, currentThread, "OSLockMutex(): current thread does not exist.");
|
||||
ASSERTMSGLINE(148, currentThread->state == 2, "OSLockMutex(): current thread is not running.");
|
||||
|
||||
while (1) {
|
||||
OSThread* ownerThread = ((volatile OSMutex*)mutex)->thread;
|
||||
if (ownerThread == 0) {
|
||||
mutex->thread = currentThread;
|
||||
mutex->count++;
|
||||
ENQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link);
|
||||
break;
|
||||
} else if (ownerThread == currentThread) {
|
||||
mutex->count++;
|
||||
break;
|
||||
} else {
|
||||
currentThread->mutex = mutex;
|
||||
__OSPromoteThread(mutex->thread, currentThread->priority);
|
||||
ASSERTMSG2LINE(170, __OSCheckDeadLock(currentThread) == 0, "OSLockMutex(): detected deadlock: current thread %p, mutex %p.", currentThread, mutex);
|
||||
OSSleepThread(&mutex->queue);
|
||||
currentThread->mutex = NULL;
|
||||
}
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSUnlockMutex(OSMutex* mutex) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(195, currentThread, "OSUnlockMutex(): current thread does not exist.");
|
||||
ASSERTMSGLINE(197, currentThread->state == 2, "OSUnlockMutex(): current thread is not running.");
|
||||
ASSERTMSG2LINE(200, mutex->thread == currentThread, "OSUnlockMutex(): current thread %p is not the owner of mutex %p.", currentThread, mutex);
|
||||
|
||||
if (mutex->thread == currentThread) {
|
||||
if (!--mutex->count) {
|
||||
DEQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link);
|
||||
mutex->thread = 0;
|
||||
|
||||
if (currentThread->priority < currentThread->base) {
|
||||
currentThread->priority = __OSGetEffectivePriority(currentThread);
|
||||
}
|
||||
OSWakeupThread(&mutex->queue);
|
||||
}
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void __OSUnlockAllMutex(OSThread* thread) {
|
||||
OSMutex* mutex;
|
||||
|
||||
while (thread->queueMutex.head) {
|
||||
mutex = thread->queueMutex.head;
|
||||
DEQUEUE_HEAD(mutex, &thread->queueMutex, link);
|
||||
ASSERTLINE(235, mutex->thread == thread);
|
||||
mutex->count = 0;
|
||||
mutex->thread = 0;
|
||||
OSWakeupThread(&mutex->queue);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL OSTryLockMutex(OSMutex* mutex) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
BOOL locked;
|
||||
|
||||
ASSERTMSGLINE(261, currentThread, "OSTryLockMutex(): current thread does not exist.");
|
||||
ASSERTMSGLINE(263, currentThread->state == 2, "OSTryLockMutex(): current thread is not running.");
|
||||
|
||||
if (!mutex->thread) {
|
||||
mutex->thread = currentThread;
|
||||
mutex->count++;
|
||||
ENQUEUE_MUTEX(mutex, ¤tThread->queueMutex, 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();
|
||||
|
||||
ASSERTMSGLINE(319, currentThread, "OSWaitCond(): current thread does not exist.");
|
||||
ASSERTMSGLINE(321, currentThread->state == 2, "OSWaitCond(): current thread is not running.");
|
||||
ASSERTMSG2LINE(324, mutex->thread == currentThread, "OSWaitCond(): current thread %p is not the owner of mutex %p.", currentThread, mutex);
|
||||
|
||||
if (mutex->thread == currentThread) {
|
||||
s32 count = mutex->count;
|
||||
mutex->count = 0;
|
||||
DEQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link);
|
||||
mutex->thread = 0;
|
||||
if (currentThread->priority < currentThread->base) {
|
||||
currentThread->priority = __OSGetEffectivePriority(currentThread);
|
||||
}
|
||||
OSDisableScheduler();
|
||||
OSWakeupThread(&mutex->queue);
|
||||
OSEnableScheduler();
|
||||
OSSleepThread(&cond->queue);
|
||||
OSLockMutex(mutex);
|
||||
mutex->count = count;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSSignalCond(OSCond* cond) {
|
||||
OSWakeupThread(&cond->queue);
|
||||
}
|
||||
|
||||
static int IsMember(OSMutexQueue* queue, OSMutex* mutex) {
|
||||
OSMutex* member = queue->head;
|
||||
|
||||
while (member) {
|
||||
if (mutex == member) {
|
||||
return 1;
|
||||
}
|
||||
member = member->link.next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __OSCheckMutex(OSMutex* mutex) {
|
||||
OSThread* thread;
|
||||
OSThreadQueue* queue;
|
||||
s32 priority;
|
||||
|
||||
priority = 0;
|
||||
queue = &mutex->queue;
|
||||
|
||||
if (queue->head != NULL && queue->head->link.prev != NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (queue->tail != NULL && queue->tail->link.next != NULL) {
|
||||
return 0;
|
||||
}
|
||||
thread = queue->head;
|
||||
while (thread) {
|
||||
if (thread->link.next != NULL && (thread != thread->link.next->link.prev)) {
|
||||
return 0;
|
||||
}
|
||||
if (thread->link.prev != NULL && (thread != thread->link.prev->link.next)) {
|
||||
return 0;
|
||||
}
|
||||
if (thread->state != 4) {
|
||||
return 0;
|
||||
}
|
||||
if (thread->priority < priority) {
|
||||
return 0;
|
||||
}
|
||||
priority = thread->priority;
|
||||
thread = thread->link.next;
|
||||
}
|
||||
if (mutex->thread) {
|
||||
if (mutex->count <= 0) {
|
||||
return 0;
|
||||
}
|
||||
} else if (mutex->count != 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int __OSCheckDeadLock(OSThread* thread) {
|
||||
OSMutex* mutex = thread->mutex;
|
||||
|
||||
while (mutex && mutex->thread) {
|
||||
if (mutex->thread == thread) {
|
||||
return 1;
|
||||
}
|
||||
mutex = mutex->thread->mutex;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __OSCheckMutexes(OSThread* thread) {
|
||||
OSMutex* mutex = thread->queueMutex.head;
|
||||
|
||||
while (mutex) {
|
||||
if (mutex->thread != thread) {
|
||||
return 0;
|
||||
}
|
||||
if (__OSCheckMutex(mutex) == 0) {
|
||||
return 0;
|
||||
}
|
||||
mutex = mutex->link.next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#include <revolution/os.h>
|
||||
#include <revolution/nand.h>
|
||||
|
||||
static u32 CheckSum(OSNandbootInfo* info) {
|
||||
u32* ptr, i, sum;
|
||||
|
||||
ptr = (u32*)&(info->ArgOffset);
|
||||
sum = 0;
|
||||
for (i = 0; i < (sizeof(OSNandbootInfo) - 4) / 4; i++) {
|
||||
sum = sum + *ptr;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
BOOL __OSCreateNandbootInfo(void) {
|
||||
NANDStatus status;
|
||||
s32 result;
|
||||
|
||||
result = NANDPrivateGetStatus("/shared2/sys/NANDBOOTINFO", &status);
|
||||
if (result == 0 && status.permission == 0x3F) {
|
||||
return TRUE;
|
||||
} else if (result == 0 && status.permission != 0x3F) {
|
||||
result = NANDPrivateDelete("/shared2/sys/NANDBOOTINFO");
|
||||
if (result != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
} else if (result == -12) {
|
||||
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = NANDPrivateCreate("/shared2/sys/NANDBOOTINFO", 63, 0);
|
||||
if (result != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL __OSWriteNandbootInfo(OSNandbootInfo* info) {
|
||||
NANDFileInfo fileInfo;
|
||||
s32 result;
|
||||
|
||||
ASSERTMSGLINE(145, !((u32)info & 0x1F), "OSNandbootInfo needs 32 byte alignment.");
|
||||
info->CheckSum = CheckSum(info);
|
||||
result = NANDPrivateOpen("/shared2/sys/NANDBOOTINFO", &fileInfo, 2);
|
||||
|
||||
if (result == 0) {
|
||||
result = NANDWrite(&fileInfo, info, sizeof(OSNandbootInfo));
|
||||
if (result != sizeof(OSNandbootInfo)) {
|
||||
NANDClose(&fileInfo);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = NANDClose(&fileInfo);
|
||||
if (result != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
#include <revolution/os.h>
|
||||
#include <revolution/sc.h>
|
||||
#include <revolution/private/iosresclt.h>
|
||||
|
||||
static OSShutdownFunctionInfo ShutdownFuncInfo;
|
||||
|
||||
static IOSFd nwc24ShtFd = -1;
|
||||
static int nwc24ShtRetryRest = 0;
|
||||
static BOOL NWC24iIsRequestPending = FALSE;
|
||||
|
||||
typedef enum NWC24Err {
|
||||
NWC24_OK = 0,
|
||||
} NWC24Err;
|
||||
|
||||
NWC24Err NWC24iPrepareShutdown(void);
|
||||
NWC24Err NWC24iSynchronizeRtcCounter(BOOL);
|
||||
NWC24Err NWC24iOpenResourceManager_(const char* callerName, const char* path, IOSFd* fd, u32 flags);
|
||||
NWC24Err NWC24SuspendScheduler(void);
|
||||
NWC24Err NWC24iSetRtcCounter_(int rtc, BOOL);
|
||||
NWC24Err NWC24iIoctlResourceManager_(const char* callerName, IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen);
|
||||
NWC24Err NWC24iCloseResourceManager_(const char* callerName, IOSFd);
|
||||
NWC24Err NWC24iRequestShutdown(u32 event, s32* result);
|
||||
NWC24Err NWC24iIoctlResourceManagerAsync_(const char* callerName, IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen, void* cbArg);
|
||||
BOOL NWC24iIsAsyncRequestPending_(void);
|
||||
|
||||
BOOL NWC24Shutdown_(BOOL, u32);
|
||||
|
||||
static void REXInit(void);
|
||||
static NWC24Err GetRTC(int* rtc);
|
||||
static s32 CheckCallingStatus(const char* callerName);
|
||||
static IOSError CallbackAsyncIpc(IOSError, void*);
|
||||
|
||||
void __OSInitNet(void) {
|
||||
NWC24Err cur_err;
|
||||
s32 res;
|
||||
OSIOSRev iosRev;
|
||||
|
||||
REXInit();
|
||||
__OSGetIOSRev(&iosRev);
|
||||
|
||||
if (iosRev.major <= 4 || iosRev.major == 9) {
|
||||
return;
|
||||
}
|
||||
|
||||
cur_err = NWC24iPrepareShutdown();
|
||||
|
||||
if (cur_err != NWC24_OK) {
|
||||
if (cur_err < NWC24_OK) {
|
||||
OSReport("Failed to register network shutdown function. %d\n", cur_err);
|
||||
}
|
||||
|
||||
res = NWC24SuspendScheduler();
|
||||
if (res < NWC24_OK) {
|
||||
OSReport("Failed to suspend the WiiConnect24 scheduler. %d\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
if (!__OSInIPL) {
|
||||
cur_err = NWC24iSynchronizeRtcCounter(0);
|
||||
|
||||
if (cur_err != NWC24_OK) {
|
||||
OSReport("Failed to synchronize time with network resource managers. %d\n", cur_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void REXInit(void) {}
|
||||
|
||||
NWC24Err NWC24iPrepareShutdown(void) {
|
||||
NWC24Err rt = NWC24_OK;
|
||||
ShutdownFuncInfo.func = NWC24Shutdown_;
|
||||
ShutdownFuncInfo.priority = 110;
|
||||
OSRegisterShutdownFunction(&ShutdownFuncInfo);
|
||||
|
||||
if (nwc24ShtFd < 0) {
|
||||
rt = NWC24iOpenResourceManager_("NWC24iPrepareShutdown", "/dev/net/kd/request", &nwc24ShtFd, 1);
|
||||
}
|
||||
|
||||
nwc24ShtRetryRest = 5;
|
||||
|
||||
if (rt == NWC24_OK) {
|
||||
rt = 1;
|
||||
}
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
NWC24Err NWC24iSynchronizeRtcCounter(BOOL param_0) {
|
||||
NWC24Err rt;
|
||||
int rtc;
|
||||
|
||||
rt = GetRTC(&rtc);
|
||||
if (rt != NWC24_OK) {
|
||||
return rt;
|
||||
}
|
||||
|
||||
return NWC24iSetRtcCounter_(rtc, param_0 ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
NWC24Err NWC24SuspendScheduler(void) {
|
||||
static u8 susResult[0x20] __attribute__ ((aligned(32)));
|
||||
NWC24Err rt = NWC24_OK;
|
||||
NWC24Err closeRt = NWC24_OK;
|
||||
IOSFd fd;
|
||||
|
||||
rt = CheckCallingStatus("NWC24SuspendScheduler");
|
||||
if (rt < NWC24_OK) {
|
||||
return rt;
|
||||
}
|
||||
|
||||
rt = NWC24iOpenResourceManager_("NWC24SuspendScheduler", "/dev/net/kd/request", &fd, 0);
|
||||
if (rt >= NWC24_OK) {
|
||||
rt = NWC24iIoctlResourceManager_("NWC24SuspendScheduler", fd, 1, NULL, 0, &susResult, sizeof(susResult));
|
||||
if (rt >= NWC24_OK) {
|
||||
rt = *(NWC24Err*)susResult;
|
||||
}
|
||||
|
||||
closeRt = NWC24iCloseResourceManager_("NWC24SuspendScheduler", fd);
|
||||
if (closeRt < NWC24_OK) {
|
||||
rt = closeRt;
|
||||
}
|
||||
}
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
void dummyStrings() {
|
||||
OSReport("NWC24ResumeScheduler");
|
||||
}
|
||||
|
||||
NWC24Err NWC24iRequestShutdown(u32 event, s32* result) {
|
||||
static u32 shtBuffer[8];
|
||||
static u32 shtResult[8];
|
||||
NWC24Err ret = NWC24_OK;
|
||||
NWC24Err var_r30 = NWC24_OK;
|
||||
|
||||
shtBuffer[0] = event;
|
||||
ret = NWC24iIoctlResourceManagerAsync_("NWC24iRequestShutdown", nwc24ShtFd, 0x28, shtBuffer, 0x20, shtResult, 0x20, result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL NWC24Shutdown_(BOOL final, u32 event) {
|
||||
static BOOL shuttingdown;
|
||||
static s32 result;
|
||||
|
||||
if (final) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (shuttingdown) {
|
||||
if (NWC24iIsAsyncRequestPending_()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (result >= 0) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (nwc24ShtRetryRest > 0) {
|
||||
shuttingdown = FALSE;
|
||||
nwc24ShtRetryRest--;
|
||||
} else {
|
||||
OSReport("NWC24Shutdown_: Give up!\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (NWC24iRequestShutdown(event, &result) >= NWC24_OK) {
|
||||
shuttingdown = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static u32 nwc24TimeCommonBuffer[8];
|
||||
static u32 nwc24TimeCommonResult[8];
|
||||
|
||||
NWC24Err NWC24iSetRtcCounter_(int rtc, BOOL param_1) {
|
||||
NWC24Err rt = NWC24_OK;
|
||||
NWC24Err closeRt = NWC24_OK;
|
||||
IOSFd fd;
|
||||
|
||||
rt = CheckCallingStatus("NWC24iSetRtcCounter_");
|
||||
if (rt < NWC24_OK) {
|
||||
return rt;
|
||||
}
|
||||
|
||||
rt = NWC24iOpenResourceManager_("NWC24iSetRtcCounter_", "/dev/net/kd/time", &fd, 0);
|
||||
if (rt >= NWC24_OK) {
|
||||
nwc24TimeCommonBuffer[0] = rtc;
|
||||
nwc24TimeCommonBuffer[1] = param_1;
|
||||
|
||||
rt = NWC24iIoctlResourceManager_("NWC24iSetRtcCounter_", fd, 0x17, &nwc24TimeCommonBuffer, sizeof(nwc24TimeCommonBuffer), &nwc24TimeCommonResult, sizeof(nwc24TimeCommonResult));
|
||||
if (rt >= NWC24_OK) {
|
||||
rt = *(int*)nwc24TimeCommonResult;
|
||||
}
|
||||
|
||||
closeRt = NWC24iCloseResourceManager_("NWC24iSetRtcCounter_", fd);
|
||||
if (rt >= NWC24_OK) {
|
||||
rt = closeRt;
|
||||
}
|
||||
}
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
NWC24Err NWC24iOpenResourceManager_(const char* callerName, const char* path, IOSFd* fd, u32 flags) {
|
||||
if (fd == 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
*fd = IOS_Open(path, flags);
|
||||
if (*fd < IOS_ERROR_OK) {
|
||||
if (*fd == IOS_ERROR_NOEXISTS) {
|
||||
OSReport("%s() %s\n", callerName, "Firmware is still in progress.");
|
||||
return -29;
|
||||
} else {
|
||||
OSReport("%s() %s (%d)\n", callerName, "IOS_Open failure.", *fd);
|
||||
return -42;
|
||||
}
|
||||
}
|
||||
|
||||
return NWC24_OK;
|
||||
}
|
||||
|
||||
NWC24Err NWC24iCloseResourceManager_(const char* callerName, IOSFd fd) {
|
||||
int rt = IOS_Close(fd);
|
||||
if (rt < IOS_ERROR_OK) {
|
||||
OSReport("%s() %s (%d)\n", callerName, "IOS_Close failure.", rt);
|
||||
return -42;
|
||||
}
|
||||
|
||||
return NWC24_OK;
|
||||
}
|
||||
|
||||
// NOTE: function doesn't exist in TP debug, stub for string data
|
||||
NWC24Err NWC24iCloseResourceManagerAsync_(const char* callerName, IOSFd fd) {
|
||||
OSReport("IOS_CloseAsync failure.");
|
||||
return NWC24_OK;
|
||||
}
|
||||
|
||||
NWC24Err NWC24iIoctlResourceManager_(const char* callerName, IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen) {
|
||||
int rt = IOS_Ioctl(fd, cmd, input, inputLen, output, outputLen);
|
||||
if (rt < IOS_ERROR_OK) {
|
||||
OSReport("%s() %s (%d)\n", callerName, "IOS_Ioctl failure.", rt);
|
||||
return -42;
|
||||
}
|
||||
|
||||
return NWC24_OK;
|
||||
}
|
||||
|
||||
NWC24Err NWC24iIoctlResourceManagerAsync_(const char* callerName, IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen, void* cbArg) {
|
||||
int rt = IOS_IoctlAsync(fd, cmd, input, inputLen, output, outputLen, CallbackAsyncIpc, cbArg);
|
||||
if (rt < IOS_ERROR_OK) {
|
||||
OSReport("%s() %s (%d)\n", callerName, "IOS_IoctlAsync failure.", rt);
|
||||
return -42;
|
||||
}
|
||||
|
||||
NWC24iIsRequestPending = TRUE;
|
||||
return NWC24_OK;
|
||||
}
|
||||
|
||||
BOOL NWC24iIsAsyncRequestPending_(void) {
|
||||
return NWC24iIsRequestPending;
|
||||
}
|
||||
|
||||
static IOSError CallbackAsyncIpc(IOSError param_0, void* param_1) {
|
||||
if (param_1 != 0) {
|
||||
*(IOSError*)param_1 = param_0;
|
||||
}
|
||||
|
||||
NWC24iIsRequestPending = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 CheckCallingStatus(const char* callerName) {
|
||||
if (OSGetCurrentThread() == 0) {
|
||||
OSReport("%s() %s\n", callerName, "Illegal status. Unavailable from exception handler.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static NWC24Err GetRTC(int* rtc) {
|
||||
OSTime time;
|
||||
u32 bias;
|
||||
u32 status;
|
||||
do {
|
||||
status = SCCheckStatus();
|
||||
if (status == 2) {
|
||||
return -1;
|
||||
}
|
||||
} while (status != 0);
|
||||
|
||||
bias = SCGetCounterBias();
|
||||
time = OSGetTime();
|
||||
*rtc = (time / OS_TIMER_CLOCK) - bias;
|
||||
return NWC24_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
#include <revolution/os/OSPlayRecord.h>
|
||||
#include <revolution/nand.h>
|
||||
|
||||
static BOOL PlayRecordGet = FALSE;
|
||||
static OSPlayRecord PlayRecord __attribute__ ((aligned(32)));
|
||||
static NANDFileInfo FileInfo;
|
||||
static NANDCommandBlock Block;
|
||||
static s32 PlayRecordState = 9;
|
||||
static OSAlarm PlayRecordAlarm;
|
||||
static BOOL PlayRecordError = FALSE;
|
||||
static volatile BOOL PlayRecordTerminate = FALSE;
|
||||
static volatile BOOL PlayRecordTerminated = FALSE;
|
||||
static BOOL PlayRecordRetry = FALSE;
|
||||
static OSTime PlayRecordLastCloseTime;
|
||||
static s32 PlayRecordLastError = NAND_RESULT_OK;
|
||||
|
||||
static void PlayRecordCallback(s32, NANDCommandBlock *);
|
||||
|
||||
static u32 RecordCheckSum(OSPlayRecord* record) {
|
||||
u32 *ptr, i, sum;
|
||||
ptr = (u32*)record->titleName;
|
||||
sum = 0;
|
||||
|
||||
for (i = 0; i < (sizeof(PlayRecord) - 4) / 4; i++) {
|
||||
sum = sum + *ptr;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
void PlayRecordAlarmCallback(OSAlarm* alarm, OSContext* context) {
|
||||
PlayRecordCallback(NAND_RESULT_OK, NULL);
|
||||
}
|
||||
|
||||
static void PlayRecordCallback(s32 result, NANDCommandBlock* block) {
|
||||
s32 ret = 0;
|
||||
PlayRecordLastError = result;
|
||||
|
||||
if (PlayRecordTerminate) {
|
||||
PlayRecordTerminated = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlayRecordRetry) {
|
||||
switch (PlayRecordState) {
|
||||
case 0:
|
||||
PlayRecordState = 1;
|
||||
break;
|
||||
case 1:
|
||||
if (result == NAND_RESULT_MAXFD) {
|
||||
PlayRecordRetry = TRUE;
|
||||
OSCreateAlarm(&PlayRecordAlarm);
|
||||
OSSetAlarm(&PlayRecordAlarm, (OSTime)1 * OSSecondsToTicks(1), PlayRecordAlarmCallback);
|
||||
return;
|
||||
}
|
||||
else if (result == NAND_RESULT_OK) {
|
||||
if (!PlayRecordGet) {
|
||||
PlayRecordState = 2;
|
||||
}
|
||||
else {
|
||||
PlayRecordState = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
PlayRecordError = TRUE;
|
||||
PlayRecordState = 7;
|
||||
return;
|
||||
}
|
||||
case 2:
|
||||
if (result == sizeof(OSPlayRecord)) {
|
||||
PlayRecordGet = TRUE;
|
||||
PlayRecordLastCloseTime = PlayRecord.playTime;
|
||||
PlayRecordState = 3;
|
||||
}
|
||||
else {
|
||||
PlayRecordError = TRUE;
|
||||
PlayRecordState = 6;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (result == 0) {
|
||||
PlayRecordState = 4;
|
||||
}
|
||||
else {
|
||||
PlayRecordError = TRUE;
|
||||
PlayRecordState = 6;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
PlayRecordState = 5;
|
||||
break;
|
||||
case 5:
|
||||
if (result == sizeof(OSPlayRecord)) {
|
||||
if (OSGetTime() - PlayRecordLastCloseTime > (OSTime)300 * OSSecondsToTicks(1)) {
|
||||
PlayRecordState = 6;
|
||||
}
|
||||
else {
|
||||
PlayRecordState = 3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PlayRecordError = TRUE;
|
||||
PlayRecordState = 6;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (PlayRecordError) {
|
||||
PlayRecordState = 7;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (result == NAND_RESULT_OK) {
|
||||
PlayRecordLastCloseTime = PlayRecord.playTime;
|
||||
PlayRecordState = 1;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
PlayRecordState = 7;
|
||||
PlayRecordError = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
default:
|
||||
PlayRecordState = 7;
|
||||
PlayRecordError = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PlayRecordRetry = FALSE;
|
||||
|
||||
switch (PlayRecordState) {
|
||||
case 1:
|
||||
ret = NANDOpenAsync("/title/00000001/00000002/data/play_rec.dat", &FileInfo, 3, PlayRecordCallback, &Block);
|
||||
break;
|
||||
case 2:
|
||||
ret = NANDReadAsync(&FileInfo, &PlayRecord, sizeof(OSPlayRecord), PlayRecordCallback, &Block);
|
||||
break;
|
||||
case 3:
|
||||
ret = NANDSeekAsync(&FileInfo, 0, 0, PlayRecordCallback, &Block);
|
||||
break;
|
||||
case 4:
|
||||
OSCreateAlarm(&PlayRecordAlarm);
|
||||
OSSetAlarm(&PlayRecordAlarm, (OSTime)60 * OSSecondsToTicks(1), PlayRecordAlarmCallback);
|
||||
break;
|
||||
case 5:
|
||||
PlayRecord.playTime = OSGetTime();
|
||||
PlayRecord.checkSum = RecordCheckSum(&PlayRecord);
|
||||
ret = NANDWriteAsync(&FileInfo, &PlayRecord, sizeof(OSPlayRecord), PlayRecordCallback, &Block);
|
||||
break;
|
||||
case 6:
|
||||
ret = NANDCloseAsync(&FileInfo, PlayRecordCallback, &Block);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != NAND_RESULT_OK) {
|
||||
if (ret == NAND_RESULT_BUSY) {
|
||||
OSCreateAlarm(&PlayRecordAlarm);
|
||||
OSSetAlarm(&PlayRecordAlarm, (OSTime)1 * OSSecondsToTicks(1), PlayRecordAlarmCallback);
|
||||
PlayRecordRetry = TRUE;
|
||||
}
|
||||
else {
|
||||
PlayRecordError = TRUE;
|
||||
switch (PlayRecordState) {
|
||||
case 2:
|
||||
case 3:
|
||||
case 5:
|
||||
PlayRecordState = 6;
|
||||
ret = NANDCloseAsync(&FileInfo, PlayRecordCallback, &Block);
|
||||
|
||||
if (ret == NAND_RESULT_BUSY) {
|
||||
PlayRecordRetry = TRUE;
|
||||
OSCreateAlarm(&PlayRecordAlarm);
|
||||
OSSetAlarm(&PlayRecordAlarm, 1 * OSSecondsToTicks(1), PlayRecordAlarmCallback);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PlayRecordState = 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlayRecordLastError = ret;
|
||||
}
|
||||
|
||||
void __OSStartPlayRecord(void) {
|
||||
if (NANDInit() == NAND_RESULT_OK) {
|
||||
PlayRecordGet = FALSE;
|
||||
PlayRecordState = 0;
|
||||
PlayRecordError = FALSE;
|
||||
PlayRecordRetry = FALSE;
|
||||
PlayRecordTerminate = FALSE;
|
||||
PlayRecordTerminated = FALSE;
|
||||
PlayRecordLastError = NAND_RESULT_OK;
|
||||
PlayRecordCallback(NAND_RESULT_OK, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void __OSStopPlayRecord(void) {
|
||||
BOOL old;
|
||||
OSTime start;
|
||||
|
||||
old = OSDisableInterrupts();
|
||||
|
||||
PlayRecordTerminate = TRUE;
|
||||
|
||||
if (PlayRecordState == 7 || PlayRecordState == 0 ||
|
||||
PlayRecordState == 9 || PlayRecordState == 8)
|
||||
{
|
||||
OSRestoreInterrupts(old);
|
||||
}
|
||||
else if (PlayRecordState == 4) {
|
||||
OSCancelAlarm(&PlayRecordAlarm);
|
||||
OSRestoreInterrupts(old);
|
||||
PlayRecord.playTime = OSGetTime();
|
||||
PlayRecord.checkSum = RecordCheckSum(&PlayRecord);
|
||||
NANDWrite(&FileInfo, &PlayRecord, sizeof(PlayRecord));
|
||||
NANDClose(&FileInfo);
|
||||
} else {
|
||||
if (PlayRecordRetry) {
|
||||
OSCancelAlarm(&PlayRecordAlarm);
|
||||
OSRestoreInterrupts(old);
|
||||
} else {
|
||||
OSRestoreInterrupts(old);
|
||||
start = OSGetTime();
|
||||
while (1) {
|
||||
if (PlayRecordTerminated) {
|
||||
break;
|
||||
}
|
||||
if ((OSGetTime() - start) > OSMillisecondsToTicks(500)) {
|
||||
PlayRecordState = 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (PlayRecordState) {
|
||||
case 2:
|
||||
case 3:
|
||||
case 5:
|
||||
NANDClose(&FileInfo);
|
||||
break;
|
||||
case 1:
|
||||
if (PlayRecordLastError == NAND_RESULT_OK && !PlayRecordRetry) {
|
||||
NANDClose(&FileInfo);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (PlayRecordRetry) {
|
||||
NANDClose(&FileInfo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PlayRecordState = 9;
|
||||
}
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
#include <revolution/ai.h>
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/esp.h>
|
||||
#include <revolution/nand.h>
|
||||
|
||||
OSAlarm __OSExpireAlarm;
|
||||
OSTime __OSExpireTime;
|
||||
OSPlayTimeCallbackFunc __OSExpireCallback;
|
||||
BOOL __OSExpireSetExpiredFlag;
|
||||
|
||||
static void __OSPlayTimeRebootCallback(OSAlarm *, OSContext *);
|
||||
static void* __OSPlayTimeRebootThread(void *);
|
||||
|
||||
extern void __OSHotResetForError(void);
|
||||
|
||||
typedef struct {
|
||||
s16 new_ai_buffer[2][48*2*3];
|
||||
s32 idx_ai_buffer;
|
||||
s16* src_buffer;
|
||||
u32 frames;
|
||||
s16 aLeft;
|
||||
s16 aRight;
|
||||
AIDCallback gameAIDCallback;
|
||||
} __OSExpireAIFadeStruct;
|
||||
|
||||
static __OSExpireAIFadeStruct* __OSExpireAIFade = NULL;
|
||||
|
||||
BOOL OSPlayTimeIsLimited() {
|
||||
return __OSExpireTime != 0;
|
||||
}
|
||||
|
||||
static void __OSPlayTimeRebootCallback(OSAlarm* alarm, OSContext* context) {
|
||||
void* arenaHi;
|
||||
u32 memSize;
|
||||
OSThread* thread;
|
||||
void* stack;
|
||||
|
||||
for (thread = __OSActiveThreadQueue.head; thread; thread = thread->linkActive.next) {
|
||||
OSSuspendThread(thread);
|
||||
}
|
||||
|
||||
memSize = OSRoundUp32B(sizeof(OSThread)) + 0x1000;
|
||||
arenaHi = *(void**)OSPhysicalToCached(0x3128);
|
||||
arenaHi = (void*)((u32)arenaHi - memSize);
|
||||
|
||||
thread = (OSThread*)arenaHi;
|
||||
arenaHi = (void*)((u32)arenaHi + OSRoundUp32B(sizeof(OSThread)));
|
||||
stack = arenaHi;
|
||||
|
||||
if (!OSCreateThread(thread, __OSPlayTimeRebootThread, NULL, (void*)((u32)stack + 0x1000), 0x1000, 0, 0)) {
|
||||
__OSHotResetForError();
|
||||
}
|
||||
|
||||
OSResumeThread(thread);
|
||||
}
|
||||
|
||||
void __OSPlayTimeFadeLastAIDCallback(void) {
|
||||
if (__OSExpireAIFade->gameAIDCallback) {
|
||||
__OSExpireAIFade->gameAIDCallback();
|
||||
}
|
||||
|
||||
if (__OSExpireAIFade->frames == 0) {
|
||||
__OSExpireAIFade->src_buffer = (s16*)OSPhysicalToCached(AIGetDMAStartAddr());
|
||||
}
|
||||
|
||||
if (__OSExpireAIFade->frames == 1) {
|
||||
DCInvalidateRange(__OSExpireAIFade->src_buffer, 4);
|
||||
__OSExpireAIFade->aLeft = (s16)(*__OSExpireAIFade->src_buffer++);
|
||||
__OSExpireAIFade->aRight = (s16)(*__OSExpireAIFade->src_buffer);
|
||||
}
|
||||
|
||||
if (__OSExpireAIFade->frames >= 1) {
|
||||
s16* buffer = __OSExpireAIFade->new_ai_buffer[__OSExpireAIFade->idx_ai_buffer];
|
||||
s16* dest = buffer;
|
||||
u32 bytes = AIGetDMALength();
|
||||
u32 i = bytes;
|
||||
f32 delta = 0.995f;
|
||||
|
||||
while (i) {
|
||||
*dest++ = __OSExpireAIFade->aLeft;
|
||||
*dest++ = __OSExpireAIFade->aRight;
|
||||
|
||||
__OSExpireAIFade->aLeft *= delta;
|
||||
__OSExpireAIFade->aRight *= delta;
|
||||
|
||||
i -= 4;
|
||||
}
|
||||
|
||||
DCFlushRange(buffer, bytes);
|
||||
AIInitDMA((u32)buffer, bytes);
|
||||
__OSExpireAIFade->idx_ai_buffer++;
|
||||
__OSExpireAIFade->idx_ai_buffer &= 1;
|
||||
}
|
||||
|
||||
__OSExpireAIFade->frames++;
|
||||
}
|
||||
|
||||
BOOL __OSWriteExpiredFlag(void) {
|
||||
s32 rv = 0;
|
||||
NANDFileInfo nInfo;
|
||||
BOOL openNInfo = FALSE;
|
||||
u8 titleId[32] __attribute__ ((aligned(32)));
|
||||
|
||||
rv = NANDPrivateCreate("/shared2/expired", 63, 0);
|
||||
|
||||
if (rv != NAND_RESULT_OK && rv != NAND_RESULT_EXISTS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = NANDPrivateOpen("/shared2/expired", &nInfo, 2);
|
||||
|
||||
if (rv != NAND_RESULT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
openNInfo = TRUE;
|
||||
|
||||
rv = ESP_InitLib();
|
||||
if (rv != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(titleId, 0, 32);
|
||||
rv = ESP_GetTitleId((ESTitleId*)titleId);
|
||||
|
||||
if (rv != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = NANDWrite(&nInfo, titleId, 32);
|
||||
if (rv < 0) {
|
||||
goto out;
|
||||
}
|
||||
else if (rv != 32) {
|
||||
rv = NAND_RESULT_INVALID;
|
||||
goto out;
|
||||
}
|
||||
else {
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
if (openNInfo) {
|
||||
NANDClose(&nInfo);
|
||||
}
|
||||
|
||||
return rv == 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
BOOL __OSWriteExpiredFlagIfSet(void) {
|
||||
if (__OSExpireSetExpiredFlag) {
|
||||
return __OSWriteExpiredFlag();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void* __OSPlayTimeRebootThread(void* args) {
|
||||
BOOL enabled;
|
||||
u32 frames, fadeShift = 1;
|
||||
__OSExpireAIFadeStruct aiFade __attribute__ ((aligned(32)));
|
||||
|
||||
__OSExpireAIFade = &aiFade;
|
||||
memset(__OSExpireAIFade, 0, sizeof(__OSExpireAIFadeStruct));
|
||||
__OSExpireAIFade->gameAIDCallback = AIRegisterDMACallback(__OSPlayTimeFadeLastAIDCallback);
|
||||
|
||||
for (frames = 0; frames < 20; frames++) {
|
||||
fadeShift = (frames / 5) + 1;
|
||||
if (fadeShift > 7) {
|
||||
fadeShift = 7;
|
||||
}
|
||||
|
||||
VIWaitForRetrace();
|
||||
__OSSetVIForceDimming(TRUE, fadeShift, fadeShift);
|
||||
}
|
||||
|
||||
AIRegisterDMACallback(NULL);
|
||||
|
||||
VISetBlack(TRUE);
|
||||
VIFlush();
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
__OSWriteExpiredFlagIfSet();
|
||||
OSRestoreInterrupts(enabled);
|
||||
OSReturnToMenu();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __OSPlayTimeAlarmExpired(OSAlarm* alarm, OSContext* context) {
|
||||
if (__OSExpireCallback != 0) {
|
||||
__OSExpireCallback();
|
||||
} else {
|
||||
__OSPlayTimeRebootCallback(alarm, context);
|
||||
}
|
||||
}
|
||||
|
||||
static s32 __OSPlayTimeGetConsumption(ESTicketView *tk, ESLpEntry *lpEntry, u32 *nEntries) {
|
||||
s32 rv = ESP_GetConsumption(tk->ticketID, NULL, nEntries);
|
||||
|
||||
if (rv > 0) {
|
||||
goto out;
|
||||
} else if (rv != 0) {
|
||||
ASSERTMSGLINE(573, rv != -0x3F9, "Fix by calling ESP_InitLib");
|
||||
ASSERTMSG1LINE(574, FALSE, "Failed: %d\n", rv);
|
||||
rv = rv;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*nEntries != 0) {
|
||||
rv = ESP_GetConsumption(tk->ticketID, lpEntry, nEntries);
|
||||
if (rv != 0) {
|
||||
ASSERTMSG1LINE(583, FALSE, "Failed: %d\n", rv);
|
||||
rv = rv;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
s32 __OSGetPlayTime(ESTicketView* ticket, __OSPlayTimeType* type, u32* playTime) {
|
||||
s32 rv;
|
||||
u32 i;
|
||||
ESLpEntry lpEntry[8] __attribute__ ((aligned(32)));
|
||||
u32 numCc = 0, seenOther = 0;
|
||||
ESTicketView ticketAligned __attribute__ ((aligned(32)));
|
||||
|
||||
ASSERTLINE(601, ticket && type && playTime);
|
||||
|
||||
if ((u32)(ticket) & 31) {
|
||||
memcpy(&ticketAligned, ticket, sizeof(ESTicketView));
|
||||
ticket = &ticketAligned;
|
||||
}
|
||||
|
||||
rv = __OSPlayTimeGetConsumption(ticket, lpEntry, &numCc);
|
||||
if (rv != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (ticket->limits[i].code == 1) {
|
||||
*type = 1;
|
||||
|
||||
if (numCc == 0) {
|
||||
*playTime = ticket->limits[i].limit;
|
||||
} else {
|
||||
ASSERTLINE(630, i < numCc);
|
||||
|
||||
if (lpEntry[i].limit >= ticket->limits[i].limit) {
|
||||
*playTime = 0;
|
||||
} else {
|
||||
*playTime = ticket->limits[i].limit - lpEntry[i].limit;
|
||||
}
|
||||
}
|
||||
goto out;
|
||||
} else if (ticket->limits[i].code != 0) {
|
||||
seenOther = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!seenOther) {
|
||||
*type = 0;
|
||||
*playTime = 0xFFFFFFFF;
|
||||
} else {
|
||||
seenOther--;
|
||||
|
||||
if (ticket->limits[seenOther].code == 4) {
|
||||
*type = 4;
|
||||
*playTime = ticket->limits[seenOther].limit;
|
||||
|
||||
if (numCc > 0) {
|
||||
*playTime -= lpEntry[seenOther].limit;
|
||||
}
|
||||
} else {
|
||||
*type = 9;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
s32 __OSGetPlayTimeCurrent(__OSPlayTimeType* type, u32* playTime) {
|
||||
s32 rv;
|
||||
ESTicketView ticket __attribute__ ((aligned(32)));
|
||||
|
||||
ASSERTLINE(676, type && playTime);
|
||||
|
||||
rv = ESP_DiGetTicketView(NULL, &ticket);
|
||||
|
||||
if (rv == -1017) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
ASSERTMSG1LINE(687, FALSE, "Failed: %d\n", rv);
|
||||
rv = rv;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = __OSGetPlayTime(&ticket, type, playTime);
|
||||
|
||||
out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
void __OSInitPlayTime() {
|
||||
s32 rv;
|
||||
u32 limit;
|
||||
__OSPlayTimeType type;
|
||||
|
||||
__OSExpireTime = 0;
|
||||
__OSExpireCallback = NULL;
|
||||
__OSExpireSetExpiredFlag = TRUE;
|
||||
|
||||
rv = ESP_InitLib();
|
||||
if (rv != 0) {
|
||||
ASSERTMSG1LINE(710, FALSE, "Failed: %d\n", rv);
|
||||
rv = rv;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = __OSGetPlayTimeCurrent(&type, &limit);
|
||||
if (rv != 0) {
|
||||
if (rv != -1017) {
|
||||
ASSERTMSG1LINE(721, FALSE, "Failed: %d\n", rv);
|
||||
rv = rv;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (type == OSPLAYTIME_PERMANENT) {
|
||||
goto out;
|
||||
} else if (type == OSPLAYTIME_LIMITED) {
|
||||
if (limit == 0) {
|
||||
OSPanic(__FILE__, 737, "Expired");
|
||||
}
|
||||
|
||||
OSCreateAlarm(&__OSExpireAlarm);
|
||||
OSSetAlarm(&__OSExpireAlarm, OSSecondsToTicks((OSTime)limit + 20), __OSPlayTimeAlarmExpired);
|
||||
__OSExpireTime = __OSExpireAlarm.fire;
|
||||
OSReport("PlayTime: %d seconds left\n", limit);
|
||||
}
|
||||
|
||||
out:
|
||||
ESP_CloseLib();
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
static void* SaveEnd;
|
||||
static void* SaveStart;
|
||||
|
||||
void __OSReboot(u32 resetCode, u32 bootDol) {
|
||||
OSContext exceptionContext;
|
||||
char* argvToPass;
|
||||
|
||||
OSDisableInterrupts();
|
||||
OSSetArenaLo((void*)0x81280000);
|
||||
OSSetArenaHi((void*)0x812f0000);
|
||||
argvToPass = NULL;
|
||||
__OSNextPartitionType = *(u32*)0x80003194;
|
||||
__OSBootDol(bootDol, resetCode | 0x80000000, (const char**)&argvToPass);
|
||||
}
|
||||
|
||||
void OSSetSaveRegion(void* start, void* end) {
|
||||
ASSERTMSGLINE(134, (u32)start >= 0x80700000 || start == NULL, "OSSetSaveRegion(): start address should be NULL or higher than 0x80700000\n");
|
||||
ASSERTMSGLINE(135, 0x81200000 >= (u32)end || end == NULL, "OSSetSaveRegion(): end address should be NULL or lower than 0x81200000\n");
|
||||
ASSERTMSGLINE(136, ((start == NULL) ^ (end == NULL)) == 0, "OSSetSaveRegion(): if either start or end is NULL, both should be NULL\n");
|
||||
|
||||
SaveStart = start;
|
||||
SaveEnd = end;
|
||||
}
|
||||
|
||||
void OSGetSaveRegion(void** start, void** end) {
|
||||
*start = SaveStart;
|
||||
*end = SaveEnd;
|
||||
}
|
||||
|
||||
void OSGetSavedRegion(void** start, void** end) {
|
||||
*start = __OSRebootParams.regionStart;
|
||||
*end = __OSRebootParams.regionEnd;
|
||||
}
|
||||
|
|
@ -0,0 +1,339 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/sc.h>
|
||||
|
||||
#include "__os.h"
|
||||
#include "__dvd.h"
|
||||
|
||||
extern BOOL __OSInNandBoot;
|
||||
|
||||
// These macros are copied from OSThread.c. Or ARE they the same
|
||||
// macros? They dont seem to be in the SDK headers.
|
||||
#define ENQUEUE_INFO(info, queue) \
|
||||
do { \
|
||||
OSShutdownFunctionInfo* __prev = (queue)->tail; \
|
||||
if (__prev == 0) { \
|
||||
(queue)->head = (info); \
|
||||
} else { \
|
||||
__prev->next = (info); \
|
||||
} \
|
||||
(info)->prev = __prev; \
|
||||
(info)->next = 0; \
|
||||
(queue)->tail = (info); \
|
||||
} while(0);
|
||||
|
||||
#define DEQUEUE_INFO(info, queue) \
|
||||
do { \
|
||||
OSShutdownFunctionInfo* __next = (info)->next; \
|
||||
OSShutdownFunctionInfo* __prev = (info)->prev; \
|
||||
if (__next == 0) { \
|
||||
(queue)->tail = __prev; \
|
||||
} else { \
|
||||
__next->prev = __prev; \
|
||||
} \
|
||||
if (__prev == 0) { \
|
||||
(queue)->head = __next; \
|
||||
} else { \
|
||||
__prev->next = __next; \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define ENQUEUE_INFO_PRIO(info, queue) \
|
||||
do { \
|
||||
OSShutdownFunctionInfo* __prev; \
|
||||
OSShutdownFunctionInfo* __next; \
|
||||
for(__next = (queue)->head; __next \
|
||||
&& (__next->priority <= (info)->priority); \
|
||||
__next = __next->next) ; \
|
||||
\
|
||||
if (__next == 0) { \
|
||||
ENQUEUE_INFO(info, queue); \
|
||||
} else { \
|
||||
(info)->next = __next; \
|
||||
__prev = __next->prev; \
|
||||
__next->prev = (info); \
|
||||
(info)->prev = __prev; \
|
||||
if (__prev == 0) { \
|
||||
(queue)->head = (info); \
|
||||
} else { \
|
||||
__prev->next = (info); \
|
||||
} \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
static OSShutdownFunctionQueue ShutdownFunctionQueue;
|
||||
static u32 bootThisDol = 0;
|
||||
volatile BOOL __OSIsReturnToIdle = FALSE;
|
||||
|
||||
// prototypes
|
||||
static void KillThreads(void);
|
||||
static int CallResetFunctions(int final);
|
||||
static void Reset(u32 resetCode);
|
||||
|
||||
void OSRegisterShutdownFunction(OSShutdownFunctionInfo* info) {
|
||||
ASSERTLINE(373, info->func);
|
||||
|
||||
ENQUEUE_INFO_PRIO(info, &ShutdownFunctionQueue);
|
||||
}
|
||||
|
||||
void OSUnregisterShutdownFunction(OSShutdownFunctionInfo* info) {
|
||||
DEQUEUE_INFO(info, &ShutdownFunctionQueue);
|
||||
}
|
||||
|
||||
int __OSCallShutdownFunctions(BOOL final, u32 event) {
|
||||
OSShutdownFunctionInfo* info;
|
||||
int err;
|
||||
u32 priority;
|
||||
|
||||
priority = 0;
|
||||
err = 0;
|
||||
|
||||
for (info = ShutdownFunctionQueue.head; info != 0;) {
|
||||
if (err != 0 && priority != info->priority)
|
||||
break;
|
||||
err |= !info->func(final, event);
|
||||
priority = info->priority;
|
||||
info = info->next;
|
||||
}
|
||||
|
||||
err |= !__OSSyncSram();
|
||||
return err ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
void __OSShutdownDevices(u32 event) {
|
||||
int rc;
|
||||
BOOL disableRecalibration;
|
||||
BOOL doRecal;
|
||||
|
||||
switch(event) {
|
||||
case 0:
|
||||
case 5:
|
||||
case 6:
|
||||
doRecal = FALSE;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 1:
|
||||
default:
|
||||
doRecal = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
__OSStopAudioSystem();
|
||||
|
||||
if (!doRecal) {
|
||||
disableRecalibration = __PADDisableRecalibration(TRUE);
|
||||
}
|
||||
|
||||
do {} while (!__OSCallShutdownFunctions(FALSE, event));
|
||||
do {} while (!__OSSyncSram());
|
||||
|
||||
OSDisableInterrupts();
|
||||
|
||||
rc = __OSCallShutdownFunctions(TRUE, event);
|
||||
ASSERTLINE(491, rc);
|
||||
|
||||
LCDisable();
|
||||
if (!doRecal) {
|
||||
__PADDisableRecalibration(disableRecalibration);
|
||||
}
|
||||
|
||||
KillThreads();
|
||||
}
|
||||
|
||||
u8 __OSGetDiscState(u8 last) {
|
||||
u32 flags;
|
||||
|
||||
if (__DVDGetCoverStatus() != 2) {
|
||||
return 3;
|
||||
} else {
|
||||
if ((last == 1) && (__OSGetRTCFlags(&flags) && !flags)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void KillThreads(void) {
|
||||
OSThread* thread;
|
||||
OSThread* next;
|
||||
|
||||
for (thread = __OSActiveThreadQueue.head; thread; thread = next) {
|
||||
next = thread->linkActive.next;
|
||||
switch (thread->state) {
|
||||
case 1:
|
||||
case 4:
|
||||
OSCancelThread(thread);
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OSShutdownSystem(BOOL reset, u32 resetCode, BOOL forceMenu) {
|
||||
SCIdleModeInfo idleModeInfo;
|
||||
OSIOSRev iosRev;
|
||||
OSStateFlags state;
|
||||
|
||||
memset(&idleModeInfo, 0, sizeof(SCIdleModeInfo));
|
||||
|
||||
SCInit();
|
||||
while ( SCCheckStatus() == 1 )
|
||||
{}
|
||||
|
||||
SCGetIdleMode(&idleModeInfo);
|
||||
__OSStopPlayRecord();
|
||||
__OSUnRegisterStateEvent();
|
||||
__DVDPrepareReset();
|
||||
__OSReadStateFlags(&state);
|
||||
state.lastDiscState = __OSGetDiscState(state.lastDiscState);
|
||||
|
||||
if (idleModeInfo.mode == 1) {
|
||||
state.lastShutdown = 5;
|
||||
} else {
|
||||
state.lastShutdown = 1;
|
||||
}
|
||||
|
||||
__OSClearRTCFlags();
|
||||
__OSWriteStateFlags(&state);
|
||||
__OSGetIOSRev(&iosRev);
|
||||
|
||||
if (idleModeInfo.mode == 1) {
|
||||
__OSIsReturnToIdle = TRUE;
|
||||
|
||||
OSDisableScheduler();
|
||||
__OSShutdownDevices(5);
|
||||
OSEnableScheduler();
|
||||
__OSLaunchMenu();
|
||||
} else {
|
||||
OSDisableScheduler();
|
||||
__OSShutdownDevices(2);
|
||||
__OSShutdownToSBY();
|
||||
}
|
||||
}
|
||||
|
||||
void OSRestart(u32 resetCode) {
|
||||
u8 type = OSGetAppType();
|
||||
__OSStopPlayRecord();
|
||||
__OSUnRegisterStateEvent();
|
||||
|
||||
if (type == 0x81) {
|
||||
OSDisableScheduler();
|
||||
__OSShutdownDevices(4);
|
||||
OSEnableScheduler();
|
||||
__OSRelaunchTitle(resetCode);
|
||||
} else if (type == 0x80) {
|
||||
OSDisableScheduler();
|
||||
__OSShutdownDevices(4);
|
||||
OSEnableScheduler();
|
||||
__OSReboot(resetCode, bootThisDol);
|
||||
}
|
||||
|
||||
OSDisableScheduler();
|
||||
__OSShutdownDevices(1);
|
||||
__OSHotResetForError();
|
||||
}
|
||||
|
||||
void __OSReturnToMenu(u8 menuMode) {
|
||||
OSStateFlags state;
|
||||
ESTicketView* var_r30 = NULL;
|
||||
int rc;
|
||||
|
||||
__OSStopPlayRecord();
|
||||
__OSUnRegisterStateEvent();
|
||||
__DVDPrepareReset();
|
||||
__OSReadStateFlags(&state);
|
||||
|
||||
state.lastDiscState = __OSGetDiscState(state.lastDiscState);
|
||||
state.lastShutdown = 3;
|
||||
state.menuMode = menuMode;
|
||||
|
||||
__OSClearRTCFlags();
|
||||
__OSWriteStateFlags(&state);
|
||||
|
||||
OSSetArenaLo((void*)0x81280000);
|
||||
OSSetArenaHi((void*)0x812F0000);
|
||||
|
||||
rc = ESP_InitLib();
|
||||
if (rc) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
var_r30 = OSAllocFromMEM1ArenaLo(0xE0, 0x20);
|
||||
if (var_r30 == 0) {
|
||||
__OSReturnToMenuForError();
|
||||
}
|
||||
|
||||
memset(var_r30, 0, 0xE0);
|
||||
|
||||
rc = ESP_DiGetTicketView(NULL, var_r30);
|
||||
if (!rc && OSPlayTimeIsLimited()) {
|
||||
__OSPlayTimeType type = OSPLAYTIME_PERMANENT;
|
||||
u32 playTime = -1;
|
||||
__OSGetPlayTime(var_r30, &type, &playTime);
|
||||
if (playTime == 0) {
|
||||
__OSWriteExpiredFlagIfSet();
|
||||
}
|
||||
}
|
||||
|
||||
OSDisableScheduler();
|
||||
__OSShutdownDevices(5);
|
||||
OSEnableScheduler();
|
||||
|
||||
__OSLaunchMenu();
|
||||
OSDisableScheduler();
|
||||
|
||||
__VISetRGBModeImm();
|
||||
__OSHotResetForError();
|
||||
}
|
||||
|
||||
void OSReturnToMenu(void) {
|
||||
__OSReturnToMenu(0);
|
||||
OSPanic(__FILE__, 895, "OSReturnToMenu(): Falied to boot system menu.\n");
|
||||
}
|
||||
|
||||
void __OSReturnToMenuForError(void) {
|
||||
OSStateFlags state;
|
||||
__OSReadStateFlags(&state);
|
||||
|
||||
state.lastDiscState = 2;
|
||||
state.lastShutdown = 3;
|
||||
|
||||
__OSClearRTCFlags();
|
||||
__OSWriteStateFlags(&state);
|
||||
|
||||
__OSLaunchMenu();
|
||||
OSDisableScheduler();
|
||||
|
||||
__VISetRGBModeImm();
|
||||
__OSHotResetForError();
|
||||
|
||||
OSPanic(__FILE__, 1010, "__OSReturnToMenu(): Falied to boot system menu.\n");
|
||||
}
|
||||
|
||||
void __OSHotResetForError(void) {
|
||||
if (__OSInNandBoot || __OSInReboot) {
|
||||
__OSInitSTM();
|
||||
}
|
||||
|
||||
__OSHotReset();
|
||||
|
||||
OSPanic(__FILE__, 1034, "__OSHotReset(): Falied to reset system.\n");
|
||||
}
|
||||
|
||||
u32 OSGetResetCode() {
|
||||
u32 resetCode;
|
||||
if (__OSRebootParams.valid)
|
||||
resetCode = 0x80000000 | __OSRebootParams.restartCode;
|
||||
else
|
||||
resetCode = (__PIRegs[9] & 0xFFFFFFF8) / 8;
|
||||
|
||||
return resetCode;
|
||||
}
|
||||
|
||||
void OSResetSystem(int, u32, int) {
|
||||
OSPanic(__FILE__, 1185, "OSResetSystem() is obsoleted. It doesn't work any longer.\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,564 @@
|
|||
#include <revolution/exi.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
static SramControl Scb ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT);
|
||||
|
||||
// prototypes
|
||||
static int GetRTC(u32* rtc);
|
||||
static int ReadSram(void* buffer);
|
||||
static void WriteSramCallback(s32, OSContext*);
|
||||
static int WriteSram(void* buffer, u32 offset, u32 size);
|
||||
static void* LockSram(u32 offset);
|
||||
static int UnlockSram(int commit, u32 offset);
|
||||
static void __OSReadROMCallback(s32 chan);
|
||||
|
||||
static int GetRTC(u32* rtc) {
|
||||
int err;
|
||||
u32 cmd;
|
||||
|
||||
if (EXILock(0, 1, NULL) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (EXISelect(0, 1, 3) == 0) {
|
||||
EXIUnlock(0);
|
||||
return 0;
|
||||
}
|
||||
cmd = 0x20000000;
|
||||
err = 0;
|
||||
err |= !EXIImm(0, &cmd, 4, 1, 0);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIImm(0, &cmd, 4, 0, 0);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIDeselect(0);
|
||||
EXIUnlock(0);
|
||||
rtc[0] = cmd;
|
||||
return !err;
|
||||
}
|
||||
|
||||
int __OSGetRTC(u32* rtc) {
|
||||
int err;
|
||||
u32 t0;
|
||||
u32 t1;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 16; i++) {
|
||||
err = 0;
|
||||
err |= !GetRTC(&t0);
|
||||
err |= !GetRTC(&t1);
|
||||
if (err) {
|
||||
break;
|
||||
}
|
||||
if (t0 == t1) {
|
||||
rtc[0] = t0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __OSSetRTC(u32 rtc) {
|
||||
int err;
|
||||
u32 cmd;
|
||||
|
||||
if (EXILock(0, 1, NULL) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (EXISelect(0, 1, 3) == 0) {
|
||||
EXIUnlock(0);
|
||||
return 0;
|
||||
}
|
||||
cmd = 0xA0000000;
|
||||
err = 0;
|
||||
err |= !EXIImm(0, &cmd, 4, 1, 0);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIImm(0, &rtc, 4, 1, 0);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIDeselect(0);
|
||||
EXIUnlock(0);
|
||||
return !err;
|
||||
}
|
||||
|
||||
static int ReadSram(void* buffer) {
|
||||
int err;
|
||||
u32 cmd;
|
||||
|
||||
DCInvalidateRange(buffer, SRAM_SIZE);
|
||||
if (!EXILock(0, 1, NULL) ) {
|
||||
return 0;
|
||||
}
|
||||
if (!EXISelect(0, 1, 3)) {
|
||||
EXIUnlock(0);
|
||||
return 0;
|
||||
}
|
||||
cmd = 0x20000100;
|
||||
err = 0;
|
||||
err |= !EXIImm(0, &cmd, 4, 1, 0);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIDma(0, buffer, SRAM_SIZE, 0, NULL);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIDeselect(0);
|
||||
EXIUnlock(0);
|
||||
return !err;
|
||||
}
|
||||
|
||||
static void WriteSramCallback(s32, OSContext*) {
|
||||
ASSERTLINE(270, !Scb.locked);
|
||||
Scb.sync = WriteSram(&Scb.sram[Scb.offset], Scb.offset, SRAM_SIZE - Scb.offset);
|
||||
if (Scb.sync != 0) {
|
||||
Scb.offset = SRAM_SIZE;
|
||||
}
|
||||
ASSERTLINE(276, Scb.sync);
|
||||
}
|
||||
|
||||
static int WriteSram(void* buffer, u32 offset, u32 size) {
|
||||
int err;
|
||||
u32 cmd;
|
||||
|
||||
if (!EXILock(0, 1, WriteSramCallback)) {
|
||||
return 0;
|
||||
}
|
||||
if (!EXISelect(0, 1, 3)) {
|
||||
EXIUnlock(0);
|
||||
return 0;
|
||||
}
|
||||
offset <<= 6;
|
||||
cmd = ((offset + 0x100) | 0xA0000000);
|
||||
err = 0;
|
||||
err |= !EXIImm(0, &cmd, 4, 1, 0);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIImmEx(0, buffer, size, 1);
|
||||
err |= !EXIDeselect(0);
|
||||
EXIUnlock(0);
|
||||
return !err;
|
||||
}
|
||||
|
||||
void __OSInitSram(void) {
|
||||
Scb.locked = Scb.enabled = FALSE;
|
||||
Scb.sync = ReadSram(&Scb);
|
||||
ASSERTLINE(330, Scb.sync);
|
||||
Scb.offset = SRAM_SIZE;
|
||||
|
||||
OSSetGbsMode(OSGetGbsMode());
|
||||
}
|
||||
|
||||
static void* LockSram(u32 offset) {
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
ASSERTLINE(353, !Scb.locked);
|
||||
if (Scb.locked) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return NULL;
|
||||
}
|
||||
Scb.enabled = enabled;
|
||||
Scb.locked = TRUE;
|
||||
return &Scb.sram[offset];
|
||||
}
|
||||
|
||||
OSSram* __OSLockSram(void) {
|
||||
return (OSSram*)LockSram(0);
|
||||
}
|
||||
|
||||
OSSramEx* __OSLockSramEx(void) {
|
||||
return (OSSramEx*)LockSram(sizeof(OSSram));
|
||||
}
|
||||
|
||||
static int UnlockSram(int commit, u32 offset) {
|
||||
u16* p;
|
||||
|
||||
ASSERTLINE(387, Scb.locked);
|
||||
if (commit != 0) {
|
||||
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[0x14]); 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, SRAM_SIZE - Scb.offset);
|
||||
if (Scb.sync != 0) {
|
||||
Scb.offset = SRAM_SIZE;
|
||||
}
|
||||
}
|
||||
Scb.locked = FALSE;
|
||||
OSRestoreInterrupts(Scb.enabled);
|
||||
return Scb.sync;
|
||||
}
|
||||
|
||||
int __OSUnlockSram(int commit) {
|
||||
UnlockSram(commit, 0);
|
||||
}
|
||||
|
||||
int __OSUnlockSramEx(int commit) {
|
||||
UnlockSram(commit, sizeof(OSSram));
|
||||
}
|
||||
|
||||
int __OSSyncSram(void) {
|
||||
return Scb.sync;
|
||||
}
|
||||
|
||||
int __OSCheckSram(void) {
|
||||
u16* p;
|
||||
u16 checkSum;
|
||||
u16 checkSumInv;
|
||||
OSSram* sram;
|
||||
int unused;
|
||||
|
||||
ASSERTLINE(466, Scb.locked);
|
||||
|
||||
checkSum = checkSumInv = 0;
|
||||
|
||||
sram = (OSSram*)Scb.sram;
|
||||
|
||||
for (p = (void*)&sram->counterBias; p < (u16*)&Scb.sram[0x14]; p++) {
|
||||
checkSum += *p;
|
||||
checkSumInv += ~(*p);
|
||||
}
|
||||
|
||||
return (sram->checkSum == checkSum && sram->checkSumInv == checkSumInv);
|
||||
}
|
||||
|
||||
int __OSReadROM(void * buffer, s32 length, s32 offset) {
|
||||
int err;
|
||||
u32 cmd;
|
||||
|
||||
ASSERTLINE(509, length <= 1024);
|
||||
DCInvalidateRange(buffer, length);
|
||||
if (EXILock(0, 1, NULL) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (EXISelect(0, 1, 3) == 0) {
|
||||
EXIUnlock(0);
|
||||
return 0;
|
||||
}
|
||||
cmd = offset << 6;
|
||||
err = 0;
|
||||
err |= !EXIImm(0, &cmd, 4, 1, 0);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIDma(0, buffer, length, 0, NULL);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIDeselect(0);
|
||||
EXIUnlock(0);
|
||||
return !err;
|
||||
}
|
||||
|
||||
static void __OSReadROMCallback(s32 chan) {
|
||||
void (*callback)();
|
||||
|
||||
EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
callback = Scb.callback;
|
||||
if (callback) {
|
||||
Scb.callback = NULL;
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
int __OSReadROMAsync(void* buffer, s32 length, s32 offset, void (*callback)()) {
|
||||
int err;
|
||||
u32 cmd;
|
||||
|
||||
ASSERTLINE(556, length <= 1024);
|
||||
ASSERTLINE(557, callback);
|
||||
DCInvalidateRange(buffer, length);
|
||||
Scb.callback = callback;
|
||||
if (EXILock(0, 1, NULL) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (EXISelect(0, 1, 3) == 0) {
|
||||
EXIUnlock(0);
|
||||
return 0;
|
||||
}
|
||||
cmd = offset << 6;
|
||||
err = 0;
|
||||
err |= !EXIImm(0, &cmd, 4, 1, 0);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIDma(0, buffer, length, 0, (void*)__OSReadROMCallback);
|
||||
return !err;
|
||||
}
|
||||
|
||||
u32 OSGetSoundMode(void) {
|
||||
OSSram* sram = __OSLockSram();
|
||||
u32 mode = (sram->flags & 4) ? 1 : 0;
|
||||
|
||||
__OSUnlockSram(0);
|
||||
return mode;
|
||||
}
|
||||
|
||||
void OSSetSoundMode(u32 mode) {
|
||||
OSSram* sram;
|
||||
int unused;
|
||||
|
||||
ASSERTLINE(617, mode == OS_SOUND_MODE_MONO || mode == OS_SOUND_MODE_STEREO);
|
||||
mode *= 4;
|
||||
mode &= 4;
|
||||
sram = __OSLockSram();
|
||||
if (mode == (sram->flags & 4)) {
|
||||
__OSUnlockSram(0);
|
||||
return;
|
||||
}
|
||||
sram->flags &= 0xFFFFFFFB;
|
||||
sram->flags |= mode;
|
||||
__OSUnlockSram(1);
|
||||
}
|
||||
|
||||
u32 OSGetProgressiveMode(void) {
|
||||
OSSram* sram;
|
||||
u32 on;
|
||||
|
||||
sram = __OSLockSram();
|
||||
on = (sram->flags & 0x80) >> 7;
|
||||
__OSUnlockSram(FALSE);
|
||||
return on;
|
||||
}
|
||||
|
||||
void OSSetProgressiveMode(u32 on) {
|
||||
#ifndef DEBUG
|
||||
u32 padding[1];
|
||||
#endif
|
||||
OSSram* sram;
|
||||
|
||||
ASSERTLINE(670, on == OS_PROGRESSIVE_MODE_OFF || on == OS_PROGRESSIVE_MODE_ON);
|
||||
|
||||
on <<= 7;
|
||||
on &= 0x80;
|
||||
|
||||
sram = __OSLockSram();
|
||||
if (on == (sram->flags & 0x80)) {
|
||||
__OSUnlockSram(FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
sram->flags &= ~0x80;
|
||||
sram->flags |= on;
|
||||
__OSUnlockSram(TRUE);
|
||||
}
|
||||
|
||||
u32 OSGetVideoMode(void) {
|
||||
OSSram* sram = __OSLockSram();
|
||||
u32 mode = sram->flags & 3;
|
||||
|
||||
__OSUnlockSram(0);
|
||||
|
||||
if (mode > 2) {
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
void OSSetVideoMode(u32 mode) {
|
||||
OSSram* sram;
|
||||
int unused;
|
||||
|
||||
ASSERTLINE(731, OS_VIDEO_MODE_NTSC <= mode && mode <= OS_VIDEO_MODE_MPAL);
|
||||
|
||||
if (mode > 2) {
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
sram = __OSLockSram();
|
||||
|
||||
if (mode == (sram->flags & 3)) {
|
||||
__OSUnlockSram(0);
|
||||
return;
|
||||
}
|
||||
sram->flags &= 0xFFFFFFFC;
|
||||
sram->flags |= mode;
|
||||
__OSUnlockSram(1);
|
||||
}
|
||||
|
||||
u8 OSGetLanguage(void) {
|
||||
OSSram* sram = __OSLockSram();
|
||||
u8 language = sram->language;
|
||||
|
||||
__OSUnlockSram(0);
|
||||
return language;
|
||||
}
|
||||
|
||||
void OSSetLanguage(u8 language) {
|
||||
OSSram* sram = __OSLockSram();
|
||||
int unused;
|
||||
|
||||
if (language == sram->language) {
|
||||
__OSUnlockSram(0);
|
||||
return;
|
||||
}
|
||||
sram->language = language;
|
||||
__OSUnlockSram(1);
|
||||
}
|
||||
|
||||
u8 __OSGetBootMode(void) {
|
||||
OSSram* sram = __OSLockSram();
|
||||
u8 ntd = sram->ntd;
|
||||
__OSUnlockSram(0);
|
||||
return ntd & 0x80;
|
||||
}
|
||||
|
||||
void __OSSetBootMode(u8 ntd) {
|
||||
OSSram* sram;
|
||||
int unused;
|
||||
|
||||
ntd &= 0x80;
|
||||
sram = __OSLockSram();
|
||||
if (ntd == (sram->ntd & 0x80U)) {
|
||||
__OSUnlockSram(0);
|
||||
return;
|
||||
}
|
||||
sram->ntd &= 0xFFFFFF7F;
|
||||
sram->ntd |= ntd;
|
||||
__OSUnlockSram(1);
|
||||
}
|
||||
|
||||
u32 OSGetEuRgb60Mode(void) {
|
||||
OSSram* sram;
|
||||
u32 on;
|
||||
|
||||
sram = __OSLockSram();
|
||||
on = (sram->ntd & 0x40) >> 6;
|
||||
__OSUnlockSram(0);
|
||||
return on;
|
||||
}
|
||||
|
||||
void OSSetEuRgb60Mode(u32 on) {
|
||||
#ifndef DEBUG
|
||||
u32 padding[1];
|
||||
#endif
|
||||
OSSram* sram;
|
||||
|
||||
ASSERTLINE(895, on == OS_EURGB60_OFF || on == OS_EURGB60_ON);
|
||||
on <<= 6;
|
||||
on &= 0x40;
|
||||
|
||||
sram = __OSLockSram();
|
||||
if (on == (sram->ntd & 0x40)) {
|
||||
__OSUnlockSram(0);
|
||||
} else {
|
||||
sram->ntd &= ~0x40;
|
||||
sram->ntd |= on;
|
||||
__OSUnlockSram(1);
|
||||
}
|
||||
}
|
||||
|
||||
u16 OSGetWirelessID(s32 chan) {
|
||||
OSSramEx* sram;
|
||||
u16 id;
|
||||
|
||||
sram = __OSLockSramEx();
|
||||
id = sram->wirelessPadID[chan];
|
||||
__OSUnlockSramEx(FALSE);
|
||||
return id;
|
||||
}
|
||||
|
||||
void OSSetWirelessID(s32 chan, u16 id) {
|
||||
OSSramEx* sram;
|
||||
|
||||
sram = __OSLockSramEx();
|
||||
if (sram->wirelessPadID[chan] != id) {
|
||||
sram->wirelessPadID[chan] = id;
|
||||
__OSUnlockSramEx(TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
__OSUnlockSramEx(FALSE);
|
||||
}
|
||||
|
||||
u16 OSGetGbsMode(void) {
|
||||
OSSramEx* sram;
|
||||
u16 mode;
|
||||
|
||||
sram = __OSLockSramEx();
|
||||
mode = sram->gbs;
|
||||
__OSUnlockSramEx(FALSE);
|
||||
return mode;
|
||||
}
|
||||
|
||||
void OSSetGbsMode(u16 mode) {
|
||||
#ifndef DEBUG
|
||||
u32 padding[1];
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
BOOL __OSGetRTCFlags(u32* flags) {
|
||||
BOOL err;
|
||||
u32 cmd;
|
||||
|
||||
if (!EXILock(0, 1, 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!EXISelect(0, 1, 3)) {
|
||||
EXIUnlock(0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cmd = 0x21000800;
|
||||
err = FALSE;
|
||||
err |= !EXIImm(0, &cmd, 4, 1, NULL);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIImm(0, &cmd, 4, 0, NULL);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIDeselect(0);
|
||||
EXIUnlock(0);
|
||||
*flags = cmd;
|
||||
return !err;
|
||||
}
|
||||
|
||||
BOOL __OSClearRTCFlags(void) {
|
||||
BOOL err;
|
||||
u32 cmd;
|
||||
u32 data = 0;
|
||||
|
||||
if (!EXILock(0, 1, 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!EXISelect(0, 1, 3)) {
|
||||
EXIUnlock(0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cmd = 0xA1000800;
|
||||
err = FALSE;
|
||||
err |= !EXIImm(0, &cmd, 4, 1, NULL);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIImm(0, &data, 4, 1, NULL);
|
||||
err |= !EXISync(0);
|
||||
err |= !EXIDeselect(0);
|
||||
EXIUnlock(0);
|
||||
|
||||
return !err;
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#include <revolution/os.h>
|
||||
#include <revolution/nand.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static OSStateFlags StateFlags __attribute__ ((aligned(32)));
|
||||
|
||||
static u32 CheckSum(OSStateFlags* flags) {
|
||||
u32* ptr, i, sum;
|
||||
|
||||
ptr = (u32*)&flags->lastBootApp;
|
||||
sum = 0;
|
||||
|
||||
for (i = 0; i < (sizeof(OSStateFlags) - 4) / 4; i++) {
|
||||
sum = sum + *ptr;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
BOOL __OSWriteStateFlags(OSStateFlags* flags) {
|
||||
NANDFileInfo fileInfo;
|
||||
s32 result;
|
||||
|
||||
memcpy(&StateFlags, flags, sizeof(StateFlags));
|
||||
StateFlags.checkSum = CheckSum(&StateFlags);
|
||||
|
||||
result = NANDOpen("/title/00000001/00000002/data/state.dat", &fileInfo, 2);
|
||||
|
||||
if (result == 0) {
|
||||
result = NANDWrite(&fileInfo, &StateFlags, sizeof(StateFlags));
|
||||
if (result != sizeof(StateFlags)) {
|
||||
NANDClose(&fileInfo);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = NANDClose(&fileInfo);
|
||||
if (result != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL __OSReadStateFlags(OSStateFlags* flags) {
|
||||
NANDFileInfo fileInfo;
|
||||
s32 result;
|
||||
|
||||
result = NANDOpen("/title/00000001/00000002/data/state.dat", &fileInfo, 1);
|
||||
if (result == 0) {
|
||||
result = NANDRead(&fileInfo, &StateFlags, sizeof(OSStateFlags));
|
||||
NANDClose(&fileInfo);
|
||||
|
||||
if (result != sizeof(OSStateFlags)) {
|
||||
NANDDelete("/title/00000001/00000002/data/state.dat");
|
||||
memset(flags, 0, sizeof(StateFlags));
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
memset(flags, 0, sizeof(OSStateFlags));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (CheckSum(&StateFlags) != StateFlags.checkSum) {
|
||||
memset(flags, 0, sizeof(OSStateFlags));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(flags, &StateFlags, sizeof(OSStateFlags));
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
#include <revolution/os.h>
|
||||
#include <revolution/os/OSResetSW.h>
|
||||
#include <revolution/vi.h>
|
||||
|
||||
#include <revolution/private/iosrestypes.h>
|
||||
|
||||
static u32 StmImInBuf[8] __attribute__((align(32)));
|
||||
static u32 StmImOutBuf[8] __attribute__((align(32)));
|
||||
|
||||
static u32 StmVdInBuf[8] __attribute__((align(32)));
|
||||
static u32 StmVdOutBuf[8] __attribute__((align(32)));
|
||||
|
||||
static u32 StmEhInBuf[8]__attribute__((align(32)));
|
||||
static u32 StmEhOutBuf[8] __attribute__((align(32)));
|
||||
|
||||
static OSResetCallback ResetCallback;
|
||||
static OSPowerCallback PowerCallback;
|
||||
static BOOL ResetDown = 0;
|
||||
static int StmReady = 0;
|
||||
static int StmImDesc = 0;
|
||||
static int StmEhDesc = 0;
|
||||
static int StmEhRegistered = 0;
|
||||
static int StmVdInUse = 0;
|
||||
|
||||
static BOOL __OSGetResetButtonStateRaw(void);
|
||||
static s32 __OSStateEventHandler(s32, void *);
|
||||
static s32 __OSVIDimReplyHandler(s32, void *);
|
||||
static void __OSDefaultResetCallback(void);
|
||||
static void __OSDefaultPowerCallback(void);
|
||||
static void __OSRegisterStateEvent(void);
|
||||
|
||||
static void LockUp(void);
|
||||
|
||||
OSPowerCallback OSSetPowerCallback(OSPowerCallback callback) {
|
||||
BOOL enabled;
|
||||
OSPowerCallback prevCallback;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
prevCallback = PowerCallback;
|
||||
|
||||
if (callback) {
|
||||
PowerCallback = callback;
|
||||
} else {
|
||||
PowerCallback = __OSDefaultPowerCallback;
|
||||
}
|
||||
|
||||
if (!StmEhRegistered) {
|
||||
__OSRegisterStateEvent();
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
|
||||
if (prevCallback == __OSDefaultPowerCallback) {
|
||||
return NULL;
|
||||
} else {
|
||||
return prevCallback;
|
||||
}
|
||||
}
|
||||
|
||||
// NONMATCHING - regswap
|
||||
BOOL OSGetResetButtonState(void) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
int state = ResetDown;
|
||||
|
||||
ResetDown = FALSE;
|
||||
OSRestoreInterrupts(enabled);
|
||||
if (!StmEhRegistered) {
|
||||
__OSRegisterStateEvent();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
BOOL OSGetResetSwitchState(void) {
|
||||
return OSGetResetButtonState();
|
||||
}
|
||||
|
||||
int __OSInitSTM(void) {
|
||||
PowerCallback = __OSDefaultPowerCallback;
|
||||
ResetCallback = __OSDefaultResetCallback;
|
||||
ResetDown = 0;
|
||||
|
||||
if (StmReady) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
StmVdInUse = 0;
|
||||
|
||||
StmImDesc = IOS_Open("/dev/stm/immediate", 0);
|
||||
if (StmImDesc < 0) {
|
||||
OSReport("[OS] Note: STM is not included in the firmware.\n");
|
||||
StmReady = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
StmEhDesc = IOS_Open("/dev/stm/eventhook", 0);
|
||||
if (StmEhDesc < 0) {
|
||||
OSReport("[OS] Note: STM is not included in the firmware.\n");
|
||||
StmReady = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__OSRegisterStateEvent();
|
||||
StmReady = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// unknown function of origin
|
||||
void dummyStrings() {
|
||||
OSReport("Error: Failed to close STM immediate control driver. %d\n");
|
||||
OSReport("Error: Failed to close STM event hook driver. %d\n");
|
||||
}
|
||||
|
||||
void __OSShutdownToSBY(void) {
|
||||
int res;
|
||||
__VIRegs[1] = 0;
|
||||
|
||||
if (!StmReady) {
|
||||
OSPanic(__FILE__, 348, "Error: The firmware doesn\'t support shutdown feature.\n");
|
||||
}
|
||||
|
||||
StmImInBuf[0] = 0;
|
||||
res = IOS_Ioctl(StmImDesc, 0x2003, StmImInBuf, 0x20, StmImOutBuf, 0x20);
|
||||
LockUp();
|
||||
}
|
||||
|
||||
void __OSHotReset(void) {
|
||||
int result;
|
||||
__VIRegs[1] = 0;
|
||||
|
||||
if (!StmReady) {
|
||||
OSPanic(__FILE__, 412, "Error: The firmware doesn't support reboot feature.\n");
|
||||
}
|
||||
|
||||
result = IOS_Ioctl(StmImDesc, 0x2001, StmImInBuf, sizeof(StmImInBuf), StmImOutBuf, sizeof(StmImOutBuf));
|
||||
LockUp();
|
||||
}
|
||||
|
||||
BOOL __OSGetResetButtonStateRaw(void) {
|
||||
u32 reg = __PIRegs[0];
|
||||
if (!(reg & 0x10000)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
int __OSSetVIForceDimming(BOOL isEnabled, u32 yShift, u32 xShift) {
|
||||
BOOL en;
|
||||
int var_r31;
|
||||
|
||||
if (!StmReady) {
|
||||
return -10;
|
||||
}
|
||||
|
||||
en = OSDisableInterrupts();
|
||||
|
||||
if (StmVdInUse) {
|
||||
OSRestoreInterrupts(en);
|
||||
return 0;
|
||||
}
|
||||
|
||||
StmVdInUse = 1;
|
||||
OSRestoreInterrupts(en);
|
||||
|
||||
StmVdInBuf[0] = (xShift | yShift << 3) | isEnabled << 7;
|
||||
StmVdInBuf[1] = 0;
|
||||
StmVdInBuf[2] = 0;
|
||||
StmVdInBuf[3] = 0;
|
||||
StmVdInBuf[4] = 0;
|
||||
StmVdInBuf[5] = 0xFFFFFFFF;
|
||||
StmVdInBuf[6] = 0xFFFF0000;
|
||||
StmVdInBuf[7] = 0;
|
||||
|
||||
var_r31 = AccessVIDimRegs();
|
||||
return var_r31;
|
||||
}
|
||||
|
||||
s32 __OSSetIdleLEDMode(u32 led_mode) {
|
||||
s32 ret;
|
||||
|
||||
if (StmReady == 0) {
|
||||
return -6;
|
||||
}
|
||||
|
||||
StmImInBuf[0] = led_mode;
|
||||
ret = IOS_Ioctl(StmImDesc, 0x6002, StmImInBuf, 0x20, StmImOutBuf, 0x20);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 __OSUnRegisterStateEvent(void) {
|
||||
s32 ret;
|
||||
|
||||
if (StmEhRegistered == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (StmReady == 0) {
|
||||
return -6;
|
||||
}
|
||||
|
||||
ret = IOS_Ioctl(StmImDesc, 0x3002, StmImInBuf, 0x20, StmImOutBuf, 0x20);
|
||||
|
||||
if (ret == 0) {
|
||||
StmEhRegistered = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ACRWriteReg(u32 param_0, u32 param_1) {
|
||||
__IPCRegs[param_0 >> 2] = param_1;
|
||||
}
|
||||
|
||||
// NONMATCHING - extra branch
|
||||
static int AccessVIDimRegs(void) {
|
||||
int res;
|
||||
res = IOS_IoctlAsync(StmImDesc, 0x5001, StmVdInBuf, 0x20, StmVdOutBuf, 0x20, __OSVIDimReplyHandler, 0);
|
||||
switch(res) {
|
||||
default:
|
||||
return res;
|
||||
case 0:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
s32 __OSVIDimReplyHandler(s32 ret, void *pUnused) {
|
||||
StmVdInUse = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __OSRegisterStateEvent(void) {
|
||||
int err, enabled;
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
err = IOS_IoctlAsync(StmEhDesc, 0x1000, StmEhInBuf, 0x20, StmEhOutBuf, 0x20, __OSStateEventHandler, (void*)0);
|
||||
|
||||
if (err == IOS_ERROR_OK) {
|
||||
StmEhRegistered = 1;
|
||||
}
|
||||
else {
|
||||
StmEhRegistered = 0;
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void __OSDefaultResetCallback(void) {
|
||||
|
||||
}
|
||||
|
||||
void __OSDefaultPowerCallback(void) {
|
||||
|
||||
}
|
||||
|
||||
// unknown origin function
|
||||
void dummyStrings2() {
|
||||
OSReport("Error: The firmware doesn't support hot reset feature.\n");
|
||||
}
|
||||
|
||||
// NONMATCHING
|
||||
static s32 __OSStateEventHandler(s32 ret, void* pUnused) {
|
||||
int en;
|
||||
OSResetCallback cb;
|
||||
|
||||
if (ret != 0) {
|
||||
OSPanic(__FILE__, 820, "Error on STM state event handler\n");
|
||||
}
|
||||
|
||||
StmEhRegistered = 0;
|
||||
|
||||
if (StmEhOutBuf[0] == 0x20000) {
|
||||
if (__OSGetResetButtonStateRaw()) {
|
||||
en = OSDisableInterrupts();
|
||||
ResetDown = TRUE;
|
||||
cb = ResetCallback;
|
||||
ResetCallback = __OSDefaultResetCallback;
|
||||
cb();
|
||||
OSRestoreInterrupts(en);
|
||||
VIResetDimmingCount();
|
||||
}
|
||||
|
||||
__OSRegisterStateEvent();
|
||||
}
|
||||
|
||||
if (StmEhOutBuf[0] == 0x800) {
|
||||
en = OSDisableInterrupts();
|
||||
cb = PowerCallback;
|
||||
PowerCallback = __OSDefaultPowerCallback;
|
||||
cb();
|
||||
OSRestoreInterrupts(en);
|
||||
}
|
||||
|
||||
if (StmEhOutBuf[0] == 0) {}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void LockUp(void) {
|
||||
BOOL en = OSDisableInterrupts();
|
||||
|
||||
ICFlashInvalidate();
|
||||
|
||||
while (1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
void OSInitStopwatch(OSStopwatch* sw, char* name) {
|
||||
sw->name = name;
|
||||
sw->total = 0;
|
||||
sw->hits = 0;
|
||||
sw->min = 0x00000000FFFFFFFF;
|
||||
sw->max = 0;
|
||||
}
|
||||
|
||||
void OSStartStopwatch(OSStopwatch* sw) {
|
||||
sw->running = TRUE;
|
||||
sw->last = OSGetTime();
|
||||
}
|
||||
|
||||
void OSStopStopwatch(OSStopwatch* sw) {
|
||||
OSTime interval;
|
||||
|
||||
if (sw->running) {
|
||||
interval = OSGetTime() - sw->last;
|
||||
sw->total += interval;
|
||||
sw->running = FALSE;
|
||||
sw->hits++;
|
||||
if (sw->max < interval) {
|
||||
sw->max = interval;
|
||||
}
|
||||
if (interval < sw->min) {
|
||||
sw->min = interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OSTime OSCheckStopwatch(OSStopwatch* sw) {
|
||||
OSTime currTotal;
|
||||
|
||||
currTotal = sw->total;
|
||||
if (sw->running) {
|
||||
currTotal += OSGetTime() - sw->last;
|
||||
}
|
||||
return currTotal;
|
||||
}
|
||||
|
||||
void OSResetStopwatch(OSStopwatch* sw) {
|
||||
OSInitStopwatch(sw, sw->name);
|
||||
}
|
||||
|
||||
void OSDumpStopwatch(OSStopwatch* sw) {
|
||||
OSReport("Stopwatch [%s] :\n", sw->name);
|
||||
OSReport("\tTotal= %lld us\n", OSTicksToMicroseconds(sw->total));
|
||||
OSReport("\tHits = %d \n", sw->hits);
|
||||
OSReport("\tMin = %lld us\n", OSTicksToMicroseconds(sw->min));
|
||||
OSReport("\tMax = %lld us\n", OSTicksToMicroseconds(sw->max));
|
||||
OSReport("\tMean = %lld us\n", OSTicksToMicroseconds(sw->total/sw->hits));
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
// prototypes
|
||||
void __OSSystemCallVectorStart(void);
|
||||
void __OSSystemCallVectorEnd(void);
|
||||
|
||||
#ifdef __GEKKO__
|
||||
static asm void SystemCallVector(void) {
|
||||
entry __OSSystemCallVectorStart
|
||||
nofralloc
|
||||
mfspr r9, HID0
|
||||
ori r10, r9, 0x8
|
||||
mtspr HID0, r10
|
||||
isync
|
||||
sync
|
||||
mtspr HID0, r9
|
||||
rfi
|
||||
entry __OSSystemCallVectorEnd
|
||||
nop
|
||||
}
|
||||
#endif
|
||||
|
||||
void __OSInitSystemCall(void) {
|
||||
void* addr = (void*)OSPhysicalToCached(0xC00);
|
||||
|
||||
memcpy(addr, __OSSystemCallVectorStart, (u32)&__OSSystemCallVectorEnd - (u32)&__OSSystemCallVectorStart);
|
||||
DCFlushRangeNoSync(addr, 0x100);
|
||||
__sync();
|
||||
ICInvalidateRange(addr, 0x100);
|
||||
}
|
||||
|
|
@ -0,0 +1,877 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
#define ENQUEUE_THREAD(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __prev = (queue)->tail; \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = (thread); \
|
||||
} else { \
|
||||
__prev->link.next = (thread); \
|
||||
} \
|
||||
(thread)->link.prev = __prev; \
|
||||
(thread)->link.next = 0; \
|
||||
(queue)->tail = (thread); \
|
||||
} while(0);
|
||||
|
||||
#define DEQUEUE_THREAD(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __next = (thread)->link.next; \
|
||||
OSThread* __prev = (thread)->link.prev; \
|
||||
if (__next == NULL) { \
|
||||
(queue)->tail = __prev; \
|
||||
} else { \
|
||||
__next->link.prev = __prev; \
|
||||
} \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = __next; \
|
||||
} else { \
|
||||
__prev->link.next = __next; \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define ENQUEUE_THREAD_PRIO(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __prev; \
|
||||
OSThread* __next; \
|
||||
for(__next = (queue)->head; __next \
|
||||
&& (__next->priority <= (thread)->priority); \
|
||||
__next = __next->link.next) ; \
|
||||
\
|
||||
if (__next == NULL) { \
|
||||
ENQUEUE_THREAD(thread, queue, link); \
|
||||
} else { \
|
||||
(thread)->link.next = __next; \
|
||||
__prev = __next->link.prev; \
|
||||
__next->link.prev = (thread); \
|
||||
(thread)->link.prev = __prev; \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = (thread); \
|
||||
} else { \
|
||||
__prev->link.next = (thread); \
|
||||
} \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define DEQUEUE_HEAD(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __next = thread->link.next; \
|
||||
if (__next == NULL) { \
|
||||
(queue)->tail = 0; \
|
||||
} else { \
|
||||
__next->link.prev = 0; \
|
||||
} \
|
||||
(queue)->head = __next; \
|
||||
} while(0);
|
||||
|
||||
// defined in linkscript
|
||||
extern u8 _stack_end[];
|
||||
extern u8 _stack_addr[];
|
||||
|
||||
static OSThreadQueue RunQueue[32];
|
||||
static OSThread IdleThread;
|
||||
static OSThread DefaultThread;
|
||||
static OSContext IdleContext;
|
||||
static volatile u32 RunQueueBits;
|
||||
static volatile int RunQueueHint;
|
||||
static volatile s32 Reschedule;
|
||||
|
||||
#define ALIGN4(val) (((val) + 0x3) & ~0x3)
|
||||
#define ALIGN8(val) (((val) + 0x7) & ~0x7)
|
||||
|
||||
// prototypes
|
||||
static void OSInitMutexQueue(OSMutexQueue* queue);
|
||||
static void __OSSwitchThread(OSThread* nextThread);
|
||||
static int __OSIsThreadActive(OSThread* thread);
|
||||
static void SetRun(OSThread* thread);
|
||||
static void UnsetRun(OSThread* thread);
|
||||
static OSThread* SetEffectivePriority(OSThread* thread, s32 priority);
|
||||
static void UpdatePriority(OSThread* thread);
|
||||
static OSThread* SelectThread(int yield);
|
||||
static int CheckThreadQueue(OSThreadQueue* queue);
|
||||
static int IsMember(OSThreadQueue* queue, OSThread* thread);
|
||||
static void OSSetCurrentThread(OSThread* thread);
|
||||
|
||||
static void DefaultSwitchThreadCallback(OSThread* from, OSThread* to) {}
|
||||
static OSSwitchThreadCallback SwitchThreadCallback = DefaultSwitchThreadCallback;
|
||||
|
||||
OSSwitchThreadCallback OSSetSwitchThreadCallback(OSSwitchThreadCallback callback) {
|
||||
OSSwitchThreadCallback prev;
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
prev = SwitchThreadCallback;
|
||||
|
||||
SwitchThreadCallback = callback ? callback : DefaultSwitchThreadCallback;
|
||||
OSRestoreInterrupts(enabled);
|
||||
|
||||
return prev == DefaultSwitchThreadCallback ? NULL : prev;
|
||||
}
|
||||
|
||||
void __OSThreadInit() {
|
||||
OSThread* thread = &DefaultThread;
|
||||
OSPriority prio;
|
||||
|
||||
thread->state = OS_THREAD_STATE_RUNNING;
|
||||
thread->attr = 1;
|
||||
thread->priority = thread->base = 0x10;
|
||||
thread->suspend = 0;
|
||||
thread->val = (void*)-1; // wut
|
||||
thread->mutex = 0;
|
||||
|
||||
OSInitThreadQueue(&thread->queueJoin);
|
||||
#ifdef DEBUG
|
||||
OSInitMutexQueue(&thread->queueMutex);
|
||||
#else
|
||||
thread->queueMutex.head = thread->queueMutex.tail = 0; // it got inlined? cant reproduce the inline...
|
||||
#endif
|
||||
|
||||
ASSERTLINE(372, PPCMfmsr() & MSR_FP);
|
||||
|
||||
__gUnkThread1 = thread;
|
||||
OSClearContext(&thread->context);
|
||||
OSSetCurrentContext(&thread->context);
|
||||
thread->stackBase = (u8*)&_stack_addr;
|
||||
thread->stackEnd = (u32*)&_stack_end;
|
||||
*(u32*)thread->stackEnd = OS_THREAD_STACK_MAGIC;
|
||||
OSSetCurrentThread(thread);
|
||||
OSClearStack(0);
|
||||
RunQueueBits = 0;
|
||||
RunQueueHint = 0;
|
||||
|
||||
for (prio = 0; prio <= 31; prio++) {
|
||||
OSInitThreadQueue(&RunQueue[prio]);
|
||||
}
|
||||
OSInitThreadQueue(&__OSActiveThreadQueue);
|
||||
|
||||
ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
|
||||
OSClearContext(&IdleContext);
|
||||
Reschedule = 0;
|
||||
}
|
||||
|
||||
void OSSetCurrentThread(OSThread* thread) {
|
||||
SwitchThreadCallback(__OSCurrentThread, thread);
|
||||
__OSCurrentThread = thread;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
static void OSInitMutexQueue(OSMutexQueue* queue) {
|
||||
queue->head = queue->tail = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void OSInitThreadQueue(OSThreadQueue* queue) {
|
||||
queue->head = queue->tail = 0;
|
||||
}
|
||||
|
||||
OSThread* OSGetCurrentThread() {
|
||||
return __OSCurrentThread;
|
||||
}
|
||||
|
||||
static void __OSSwitchThread(OSThread* nextThread) {
|
||||
OSSetCurrentThread(nextThread);
|
||||
OSSetCurrentContext(&nextThread->context);
|
||||
OSLoadContext(&nextThread->context);
|
||||
}
|
||||
|
||||
BOOL OSIsThreadSuspended(OSThread* thread) {
|
||||
if (thread->suspend > 0) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL OSIsThreadTerminated(OSThread* thread) {
|
||||
return (thread->state == OS_THREAD_STATE_MORIBUND || thread->state == 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static BOOL __OSIsThreadActive(OSThread* thread) {
|
||||
OSThread* active;
|
||||
|
||||
if (thread->state == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (active = __OSActiveThreadQueue.head; active; active = active->linkActive.next) {
|
||||
if (thread == active) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
s32 OSDisableScheduler(void) {
|
||||
BOOL enabled;
|
||||
s32 count;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
count = Reschedule++;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return count;
|
||||
}
|
||||
|
||||
s32 OSEnableScheduler(void) {
|
||||
BOOL enabled;
|
||||
s32 count;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
count = Reschedule--;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void SetRun(OSThread* thread) {
|
||||
ASSERTLINE(569, !IsSuspended(thread->suspend));
|
||||
ASSERTLINE(570, thread->state == OS_THREAD_STATE_READY);
|
||||
|
||||
ASSERTLINE(572, OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX);
|
||||
|
||||
thread->queue = &RunQueue[thread->priority];
|
||||
|
||||
ENQUEUE_THREAD(thread, thread->queue, link);
|
||||
|
||||
RunQueueBits |= 1 << (OS_PRIORITY_MAX - thread->priority);
|
||||
RunQueueHint = 1;
|
||||
}
|
||||
|
||||
static void UnsetRun(OSThread* thread) {
|
||||
OSThreadQueue* queue;
|
||||
|
||||
ASSERTLINE(593, thread->state == OS_THREAD_STATE_READY);
|
||||
|
||||
ASSERTLINE(595, OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX);
|
||||
ASSERTLINE(596, thread->queue == &RunQueue[thread->priority]);
|
||||
|
||||
queue = thread->queue;
|
||||
|
||||
DEQUEUE_THREAD(thread, queue, link);
|
||||
|
||||
if (!queue->head) {
|
||||
RunQueueBits &= ~(1 << (OS_PRIORITY_MAX - thread->priority));
|
||||
}
|
||||
thread->queue = NULL;
|
||||
}
|
||||
|
||||
s32 __OSGetEffectivePriority(OSThread* thread) {
|
||||
s32 priority = thread->base;
|
||||
OSMutex* mutex;
|
||||
OSThread* blocked;
|
||||
|
||||
for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) {
|
||||
blocked = mutex->queue.head;
|
||||
if (blocked && blocked->priority < priority) {
|
||||
priority = blocked->priority;
|
||||
}
|
||||
}
|
||||
return priority;
|
||||
}
|
||||
|
||||
static OSThread* SetEffectivePriority(OSThread* thread, s32 priority) {
|
||||
ASSERTLINE(647, !IsSuspended(thread->suspend));
|
||||
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
UnsetRun(thread);
|
||||
thread->priority = priority;
|
||||
SetRun(thread);
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->priority = priority;
|
||||
|
||||
ENQUEUE_THREAD_PRIO(thread, thread->queue, link);
|
||||
|
||||
if (thread->mutex) {
|
||||
ASSERTLINE(662, thread->mutex->thread);
|
||||
return thread->mutex->thread;
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
RunQueueHint = 1;
|
||||
thread->priority = priority;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void UpdatePriority(OSThread* thread) {
|
||||
s32 priority;
|
||||
|
||||
while (1) {
|
||||
if(thread->suspend > 0) {
|
||||
break;
|
||||
}
|
||||
priority = __OSGetEffectivePriority(thread);
|
||||
if (thread->priority == priority) {
|
||||
break;
|
||||
}
|
||||
thread = SetEffectivePriority(thread, priority);
|
||||
if (thread == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __OSPromoteThread(OSThread* thread, s32 priority) {
|
||||
while (1) {
|
||||
if (thread->suspend > 0 || thread->priority <= priority) {
|
||||
break;
|
||||
}
|
||||
thread = SetEffectivePriority(thread, priority);
|
||||
if (thread == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static OSThread* SelectThread(int yield) {
|
||||
OSContext* currentContext;
|
||||
OSThread* currentThread;
|
||||
OSThread* nextThread;
|
||||
OSPriority priority;
|
||||
OSThreadQueue* queue;
|
||||
|
||||
if (Reschedule > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
currentContext = OSGetCurrentContext();
|
||||
currentThread = OSGetCurrentThread();
|
||||
|
||||
if (currentContext != ¤tThread->context) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (currentThread) {
|
||||
if (currentThread->state == 2) {
|
||||
if (yield == 0) {
|
||||
priority = __cntlzw(RunQueueBits);
|
||||
if (currentThread->priority <= priority)
|
||||
return NULL;
|
||||
}
|
||||
currentThread->state = OS_THREAD_STATE_READY;
|
||||
SetRun(currentThread);
|
||||
}
|
||||
if (!(currentThread->context.state & 2) && (OSSaveContext(¤tThread->context) != 0)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (RunQueueBits == 0) {
|
||||
OSSetCurrentThread(NULL);
|
||||
OSSetCurrentContext(&IdleContext);
|
||||
do {
|
||||
OSEnableInterrupts();
|
||||
while (RunQueueBits == 0) ;
|
||||
OSDisableInterrupts();
|
||||
} while (RunQueueBits == 0);
|
||||
OSClearContext(&IdleContext);
|
||||
}
|
||||
|
||||
RunQueueHint = 0;
|
||||
priority = __cntlzw(RunQueueBits);
|
||||
|
||||
ASSERTLINE(823, OS_PRIORITY_MIN <= priority && priority <= OS_PRIORITY_MAX);
|
||||
|
||||
queue = &RunQueue[priority];
|
||||
nextThread = queue->head;
|
||||
|
||||
DEQUEUE_HEAD(nextThread, queue, link);
|
||||
|
||||
ASSERTLINE(826, nextThread->priority == priority);
|
||||
|
||||
if (!queue->head) {
|
||||
RunQueueBits &= ~(1 << (OS_PRIORITY_MAX - priority));
|
||||
}
|
||||
nextThread->queue = 0;
|
||||
nextThread->state = OS_THREAD_STATE_RUNNING;
|
||||
__OSSwitchThread(nextThread);
|
||||
return nextThread;
|
||||
}
|
||||
|
||||
void __OSReschedule(void) {
|
||||
if (RunQueueHint != 0) {
|
||||
SelectThread(0);
|
||||
}
|
||||
}
|
||||
|
||||
void OSYieldThread(void) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
SelectThread(1);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param, void* stack, u32 stackSize, OSPriority priority, u16 attr) {
|
||||
BOOL enabled;
|
||||
u32 sp;
|
||||
int i;
|
||||
|
||||
ASSERTMSGLINE(910, ((priority >= OS_PRIORITY_MIN) && (priority <= OS_PRIORITY_MAX)), "OSCreateThread(): priority out of range (0 <= priority <= 31).");
|
||||
|
||||
// why check this for an assert just to check it again right after?
|
||||
if ((priority < OS_PRIORITY_MIN) || (priority > OS_PRIORITY_MAX)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
thread->state = OS_THREAD_STATE_READY;
|
||||
thread->attr = attr & 1U;
|
||||
thread->base = priority;
|
||||
thread->priority = priority;
|
||||
thread->suspend = 1;
|
||||
thread->val = (void*)-1;
|
||||
thread->mutex = 0;
|
||||
OSInitThreadQueue(&thread->queueJoin);
|
||||
#ifdef DEBUG
|
||||
OSInitMutexQueue(&thread->queueMutex);
|
||||
#else
|
||||
OSInitThreadQueue((void*)&thread->queueMutex); // why
|
||||
#endif
|
||||
sp = (u32)stack;
|
||||
sp &= ~7;
|
||||
sp -= 8;
|
||||
((u32*)sp)[0] = 0;
|
||||
((u32*)sp)[1] = 0;
|
||||
OSInitContext(&thread->context, (u32)func, sp);
|
||||
thread->context.lr = (u32)&OSExitThread;
|
||||
thread->context.gpr[3] = (u32)param;
|
||||
thread->stackBase = stack;
|
||||
thread->stackEnd = (void*)((unsigned int)stack - stackSize);
|
||||
*thread->stackEnd = OS_THREAD_STACK_MAGIC;
|
||||
thread->error = 0;
|
||||
for (i = 0; i < 2; i++) {
|
||||
thread->specific[i] = NULL;
|
||||
}
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
if (__OSErrorTable[16] != NULL) {
|
||||
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.psf[i] = (u64)0xffffffffffffffffLL;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERTMSG1LINE(964, __OSIsThreadActive(thread) == 0L, "OSCreateThread(): thread %p is still active.", thread);
|
||||
|
||||
ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OSExitThread(void* val) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(989, currentThread,
|
||||
"OSExitThread(): current thread does not exist.");
|
||||
ASSERTMSGLINE(991, currentThread->state == OS_THREAD_STATE_RUNNING,
|
||||
"OSExitThread(): current thread is not running.");
|
||||
ASSERTMSGLINE(993, __OSIsThreadActive(currentThread) != 0,
|
||||
"OSExitThread(): current thread is not active.");
|
||||
|
||||
OSClearContext(¤tThread->context);
|
||||
if (currentThread->attr & 1) {
|
||||
DEQUEUE_THREAD(currentThread, &__OSActiveThreadQueue, linkActive);
|
||||
currentThread->state = 0;
|
||||
} else {
|
||||
currentThread->state = 8;
|
||||
currentThread->val = val;
|
||||
}
|
||||
__OSUnlockAllMutex(currentThread);
|
||||
OSWakeupThread(¤tThread->queueJoin);
|
||||
RunQueueHint = 1;
|
||||
#ifdef DEBUG
|
||||
__OSReschedule();
|
||||
#else
|
||||
if (RunQueueHint != 0) {
|
||||
SelectThread(0);
|
||||
}
|
||||
#endif
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSCancelThread(OSThread* thread) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(1031, __OSIsThreadActive(thread) != 0,
|
||||
"OSExitThread(): thread %p is not active.", thread);
|
||||
|
||||
__OSCancelInternalAlarms(thread);
|
||||
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
if (thread->suspend <= 0) {
|
||||
UnsetRun(thread);
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
RunQueueHint = 1;
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->queue = 0;
|
||||
if ((thread->suspend <= 0) && (thread->mutex)) {
|
||||
ASSERTLINE(1053, thread->mutex->thread);
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OSRestoreInterrupts(enabled);
|
||||
return;
|
||||
}
|
||||
OSClearContext(&thread->context);
|
||||
if (thread->attr & 1) {
|
||||
DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
thread->state = 0;
|
||||
} else {
|
||||
thread->state = 8;
|
||||
}
|
||||
__OSUnlockAllMutex(thread);
|
||||
OSWakeupThread(&thread->queueJoin);
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int OSJoinThread(OSThread* thread, void* val) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(LINE(1061, 1092, 1092), __OSIsThreadActive(thread) != 0, "OSJoinThread(): thread %p is not active.", thread);
|
||||
|
||||
if (!(thread->attr & 1) && (thread->state != OS_THREAD_STATE_MORIBUND) && (thread->queueJoin.head == NULL)) {
|
||||
OSSleepThread(&thread->queueJoin);
|
||||
if (__OSIsThreadActive(thread) == 0) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (thread->state == OS_THREAD_STATE_MORIBUND) {
|
||||
if (val) {
|
||||
*(s32*)val = (s32)thread->val;
|
||||
}
|
||||
DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
thread->state = 0;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OSDetachThread(OSThread* thread) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(1160, __OSIsThreadActive(thread) != 0, "OSDetachThread(): thread %p is not active.", thread);
|
||||
|
||||
thread->attr |= 1;
|
||||
if (thread->state == OS_THREAD_STATE_MORIBUND) {
|
||||
DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
thread->state = 0;
|
||||
}
|
||||
OSWakeupThread(&thread->queueJoin);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
s32 OSResumeThread(OSThread* thread) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
s32 suspendCount;
|
||||
|
||||
ASSERTMSG1LINE(1189, __OSIsThreadActive(thread) != 0, "OSResumeThread(): thread %p is not active.", thread);
|
||||
ASSERTMSG1LINE(1191, thread->state != OS_THREAD_STATE_MORIBUND, "OSResumeThread(): thread %p is terminated.", thread);
|
||||
|
||||
suspendCount = thread->suspend--;
|
||||
if (thread->suspend < 0) {
|
||||
thread->suspend = 0;
|
||||
} else if (thread->suspend == 0) {
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
thread->priority = __OSGetEffectivePriority(thread);
|
||||
SetRun(thread);
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
ASSERTLINE(1206, thread->queue);
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->priority = __OSGetEffectivePriority(thread);
|
||||
ENQUEUE_THREAD_PRIO(thread, thread->queue, link);
|
||||
if (thread->mutex) {
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
}
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return suspendCount;
|
||||
}
|
||||
|
||||
s32 OSSuspendThread(OSThread* thread) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
s32 suspendCount;
|
||||
|
||||
ASSERTMSG1LINE(1240, __OSIsThreadActive(thread) != 0, "OSSuspendThread(): thread %p is not active.", thread);
|
||||
ASSERTMSG1LINE(1242, thread->state != OS_THREAD_STATE_MORIBUND, "OSSuspendThread(): thread %p is terminated.", thread);
|
||||
|
||||
suspendCount = thread->suspend++;
|
||||
if (suspendCount == 0) {
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
RunQueueHint = 1;
|
||||
thread->state = 1;
|
||||
break;
|
||||
case OS_THREAD_STATE_READY:
|
||||
UnsetRun(thread);
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->priority = 0x20;
|
||||
ENQUEUE_THREAD(thread, thread->queue, link);
|
||||
if (thread->mutex) {
|
||||
ASSERTLINE(1263, thread->mutex->thread);
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
break;
|
||||
}
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return suspendCount;
|
||||
}
|
||||
|
||||
void OSSleepThread(OSThreadQueue* queue) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(1296, currentThread, "OSSleepThread(): current thread does not exist.");
|
||||
ASSERTMSG1LINE(1298, __OSIsThreadActive(currentThread) != 0, "OSSleepThread(): current thread %p is not active.", currentThread);
|
||||
ASSERTMSG1LINE(1300, currentThread->state == OS_THREAD_STATE_RUNNING, "OSSleepThread(): current thread %p is not running.", currentThread);
|
||||
ASSERTMSG1LINE(1302, !(currentThread->suspend > 0), "OSSleepThread(): current thread %p is suspended.", currentThread);
|
||||
|
||||
currentThread->state = OS_THREAD_STATE_WAITING;
|
||||
currentThread->queue = queue;
|
||||
ENQUEUE_THREAD_PRIO(currentThread, queue, link);
|
||||
RunQueueHint = 1;
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSWakeupThread(OSThreadQueue* queue) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
while (queue->head) {
|
||||
OSThread* thread = queue->head;
|
||||
|
||||
DEQUEUE_HEAD(thread, queue, link);
|
||||
|
||||
ASSERTLINE(1331, __OSIsThreadActive(thread));
|
||||
ASSERTLINE(1332, thread->state != OS_THREAD_STATE_MORIBUND);
|
||||
ASSERTLINE(1333, thread->queue == queue);
|
||||
thread->state = OS_THREAD_STATE_READY;
|
||||
if (thread->suspend <= 0) {
|
||||
SetRun(thread);
|
||||
}
|
||||
}
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int OSSetThreadPriority(OSThread* thread, s32 priority) {
|
||||
BOOL enabled;
|
||||
|
||||
ASSERTMSGLINE(1359, (priority >= OS_PRIORITY_MIN) && (priority <= OS_PRIORITY_MAX), "OSSetThreadPriority(): priority out of range (0 <= priority <= 31).");
|
||||
|
||||
if ((priority < OS_PRIORITY_MIN) || (priority > OS_PRIORITY_MAX)) {
|
||||
return 0;
|
||||
}
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(1366, __OSIsThreadActive(thread) != 0, "OSSetThreadPriority(): thread %p is not active.", thread);
|
||||
ASSERTMSG1LINE(1368, thread->state != 8, "OSSetThreadPriority(): thread %p is terminated.", thread);
|
||||
|
||||
if (thread->base != priority) {
|
||||
thread->base = priority;
|
||||
UpdatePriority(thread);
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
s32 OSGetThreadPriority(OSThread* thread) {
|
||||
return thread->base;
|
||||
}
|
||||
|
||||
OSThread* OSSetIdleFunction(OSIdleFunction idleFunction, void* param, void* stack, u32 stackSize) {
|
||||
if (idleFunction) {
|
||||
if (IdleThread.state == 0) {
|
||||
OSCreateThread(&IdleThread, (void*)idleFunction, param, stack, stackSize, OS_PRIORITY_MAX, 1);
|
||||
OSResumeThread(&IdleThread);
|
||||
return &IdleThread;
|
||||
}
|
||||
} else if (IdleThread.state != 0) {
|
||||
OSCancelThread(&IdleThread);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OSThread* OSGetIdleFunction(void) {
|
||||
if (IdleThread.state != 0) {
|
||||
return &IdleThread;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int CheckThreadQueue(OSThreadQueue* queue) {
|
||||
OSThread* thread;
|
||||
|
||||
if ((queue->head != NULL) && (queue->head->link.prev != NULL)) {
|
||||
return 0;
|
||||
}
|
||||
if ((queue->tail != NULL) && (queue->tail->link.next != NULL)) {
|
||||
return 0;
|
||||
}
|
||||
thread = queue->head;
|
||||
while (thread) {
|
||||
if ((thread->link.next != NULL) && (thread != thread->link.next->link.prev)) {
|
||||
return 0;
|
||||
}
|
||||
if ((thread->link.prev != NULL) && (thread != thread->link.prev->link.next)) {
|
||||
return 0;
|
||||
}
|
||||
thread = thread->link.next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL IsMember(OSThreadQueue* queue, OSThread* thread) {
|
||||
OSThread* member = queue->head;
|
||||
|
||||
while (member) {
|
||||
if (thread == member) {
|
||||
return TRUE;
|
||||
}
|
||||
member = member->link.next;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// custom macro for OSCheckActiveThreads?
|
||||
#define ASSERTREPORT(line, cond) \
|
||||
if (!(cond)) { \
|
||||
OSReport("OSCheckActiveThreads: Failed " #cond " in %d\n", line); \
|
||||
OSPanic(__FILE__, line, ""); \
|
||||
}
|
||||
|
||||
s32 OSCheckActiveThreads(void) {
|
||||
OSThread* thread;
|
||||
s32 prio;
|
||||
s32 cThread;
|
||||
BOOL enabled;
|
||||
|
||||
cThread = 0;
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
for (prio = 0; prio <= OS_PRIORITY_MAX; prio++) {
|
||||
if (RunQueueBits & (1 << (OS_PRIORITY_MAX - prio))) {
|
||||
ASSERTREPORT(1522, RunQueue[prio].head != NULL && RunQueue[prio].tail != NULL);
|
||||
} else {
|
||||
ASSERTREPORT(1527, RunQueue[prio].head == NULL && RunQueue[prio].tail == NULL);
|
||||
}
|
||||
ASSERTREPORT(1529, CheckThreadQueue(&RunQueue[prio]));
|
||||
}
|
||||
|
||||
ASSERTREPORT(1534, __OSActiveThreadQueue.head == NULL || __OSActiveThreadQueue.head->linkActive.prev == NULL);
|
||||
ASSERTREPORT(1536, __OSActiveThreadQueue.tail == NULL || __OSActiveThreadQueue.tail->linkActive.next == NULL);
|
||||
|
||||
thread = __OSActiveThreadQueue.head;
|
||||
while (thread) {
|
||||
cThread++;
|
||||
ASSERTREPORT(1544, thread->linkActive.next == NULL || thread == thread->linkActive.next->linkActive.prev);
|
||||
ASSERTREPORT(1546, thread->linkActive.prev == NULL || thread == thread->linkActive.prev->linkActive.next);
|
||||
ASSERTREPORT(1549, *(thread->stackEnd) == OS_THREAD_STACK_MAGIC);
|
||||
ASSERTREPORT(1552, OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX+1);
|
||||
ASSERTREPORT(1553, 0 <= thread->suspend);
|
||||
ASSERTREPORT(1554, CheckThreadQueue(&thread->queueJoin));
|
||||
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
if (thread->suspend <= 0) {
|
||||
ASSERTREPORT(1560, thread->queue == &RunQueue[thread->priority]);
|
||||
ASSERTREPORT(1561, IsMember(&RunQueue[thread->priority], thread));
|
||||
ASSERTREPORT(1562, thread->priority == __OSGetEffectivePriority(thread));
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
ASSERTREPORT(1566, !IsSuspended(thread->suspend));
|
||||
ASSERTREPORT(1567, thread->queue == NULL);
|
||||
ASSERTREPORT(1568, thread->priority == __OSGetEffectivePriority(thread));
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
ASSERTREPORT(1571, thread->queue != NULL);
|
||||
ASSERTREPORT(1572, CheckThreadQueue(thread->queue));
|
||||
ASSERTREPORT(1573, IsMember(thread->queue, thread));
|
||||
if (thread->suspend <= 0) {
|
||||
ASSERTREPORT(1576, thread->priority == __OSGetEffectivePriority(thread));
|
||||
} else {
|
||||
ASSERTREPORT(1580, thread->priority == 32);
|
||||
}
|
||||
ASSERTREPORT(1582, !__OSCheckDeadLock(thread));
|
||||
break;
|
||||
case OS_THREAD_STATE_MORIBUND:
|
||||
ASSERTREPORT(1586, thread->queueMutex.head == NULL && thread->queueMutex.tail == NULL);
|
||||
break;
|
||||
default:
|
||||
OSReport("OSCheckActiveThreads: Failed. unkown thread state (%d) of thread %p\n", thread->state, thread);
|
||||
OSPanic(__FILE__, 1592, "");
|
||||
}
|
||||
ASSERTREPORT(1597, __OSCheckMutexes(thread));
|
||||
thread = thread->linkActive.next;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return cThread;
|
||||
}
|
||||
|
||||
void OSClearStack(u8 val) {
|
||||
register u32 sp;
|
||||
register u32* p;
|
||||
register u32 pattern;
|
||||
|
||||
pattern = (val << 24) | (val << 16) | (val << 8) | val;
|
||||
sp = OSGetStackPointer();
|
||||
for (p = __OSCurrentThread->stackEnd + 1; (u32)p < sp; ++p) {
|
||||
*p = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
void OSSetThreadSpecific(s32 index, void* ptr) {
|
||||
OSThread* thread;
|
||||
|
||||
thread = __OSCurrentThread;
|
||||
ASSERTLINE(LINE(1573, 1604, 1604), 0 <= index && index < OS_THREAD_SPECIFIC_MAX);
|
||||
|
||||
if (thread != 0 && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) {
|
||||
thread->specific[index] = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void* OSGetThreadSpecific(s32 index) {
|
||||
OSThread* thread;
|
||||
|
||||
thread = __OSCurrentThread;
|
||||
ASSERTLINE(LINE(1584, 1615, 1615), 0 <= index && index < OS_THREAD_SPECIFIC_MAX);
|
||||
|
||||
if (thread != 0 && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) {
|
||||
return thread->specific[index];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 804516D0-804516D8 000BD0 0008+00 0/0 2/1 0/0 .sbss None */
|
||||
#include "global.h"
|
||||
extern u8 Debug_BBA_804516D0;
|
||||
u8 Debug_BBA_804516D0 ALIGN_DECL(8);
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
#include <revolution/exi.h>
|
||||
#include <revolution/os.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
// End of each month in standard year
|
||||
static int YearDays[MONTH_MAX] = {0, 31, 59, 90, 120, 151,
|
||||
181, 212, 243, 273, 304, 334};
|
||||
// End of each month in leap year
|
||||
static int LeapYearDays[MONTH_MAX] = {0, 31, 60, 91, 121, 152,
|
||||
182, 213, 244, 274, 305, 335};
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm OSTime OSGetTime(void) {
|
||||
jump:
|
||||
nofralloc
|
||||
|
||||
mftbu r3
|
||||
mftb r4
|
||||
|
||||
// Check for possible carry from TBL to TBU
|
||||
mftbu r5
|
||||
cmpw r3, r5
|
||||
bne jump
|
||||
|
||||
blr
|
||||
}
|
||||
|
||||
asm OSTick OSGetTick(void){
|
||||
nofralloc
|
||||
|
||||
mftb r3
|
||||
blr
|
||||
}
|
||||
|
||||
asm static void __SetTime(OSTime time) {
|
||||
nofralloc
|
||||
li r5, 0
|
||||
mttbl r5
|
||||
mttbu r3
|
||||
mttbl r4
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
||||
void __OSSetTime(OSTime time) {
|
||||
BOOL enabled;
|
||||
OSTime * timeAdjustAddr;
|
||||
|
||||
timeAdjustAddr = __OSSystemTime;
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
*timeAdjustAddr += OSGetTime() - time;
|
||||
__SetTime(time);
|
||||
EXIProbeReset();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
OSTime __OSGetSystemTime() {
|
||||
BOOL enabled;
|
||||
OSTime* timeAdjustAddr;
|
||||
OSTime result;
|
||||
|
||||
timeAdjustAddr = __OSSystemTime;
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
result = OSGetTime() + *timeAdjustAddr;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
OSTime __OSTimeToSystemTime(OSTime time) {
|
||||
BOOL enabled;
|
||||
OSTime* timeAdjustAddr = __OSSystemTime;
|
||||
OSTime result;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
result = *timeAdjustAddr + time;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __GEKKO__
|
||||
asm void __OSSetTick(register OSTick newTicks) {
|
||||
nofralloc
|
||||
mttbl newTicks
|
||||
blr
|
||||
}
|
||||
#endif
|
||||
|
||||
static int IsLeapYear(int year) {
|
||||
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
static int GetYearDays(int year, int mon) {
|
||||
int* md = (IsLeapYear(year)) ? LeapYearDays : YearDays;
|
||||
|
||||
return md[mon];
|
||||
}
|
||||
|
||||
static int GetLeapDays(int year) {
|
||||
ASSERTLINE(292, 0 <= year);
|
||||
|
||||
if (year < 1) {
|
||||
return 0;
|
||||
}
|
||||
return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400;
|
||||
}
|
||||
|
||||
static void GetDates(int days, OSCalendarTime* td) {
|
||||
int year;
|
||||
int n;
|
||||
int month;
|
||||
int * md;
|
||||
|
||||
ASSERTLINE(317, 0 <= days);
|
||||
|
||||
td->wday = (days + 6) % WEEK_DAY_MAX;
|
||||
|
||||
for (year = days / YEAR_DAY_MAX;
|
||||
days < (n = year * YEAR_DAY_MAX + GetLeapDays(year)); year--) {
|
||||
;
|
||||
}
|
||||
|
||||
days -= n;
|
||||
td->year = year;
|
||||
td->yday = days;
|
||||
|
||||
md = IsLeapYear(year) ? LeapYearDays : YearDays;
|
||||
for (month = MONTH_MAX; days < md[--month];) {
|
||||
;
|
||||
}
|
||||
td->mon = month;
|
||||
td->mday = days - md[month] + 1;
|
||||
}
|
||||
|
||||
void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td) {
|
||||
int days;
|
||||
int secs;
|
||||
OSTime d;
|
||||
|
||||
d = ticks % OS_SEC_TO_TICKS(1);
|
||||
if (d < 0) {
|
||||
d += OS_SEC_TO_TICKS(1);
|
||||
ASSERTLINE(362, 0 <= d);
|
||||
}
|
||||
|
||||
td->usec = OS_TICKS_TO_USEC(d) % USEC_MAX;
|
||||
td->msec = OS_TICKS_TO_MSEC(d) % MSEC_MAX;
|
||||
|
||||
ASSERTLINE(366, 0 <= td->usec);
|
||||
ASSERTLINE(367, 0 <= td->msec);
|
||||
|
||||
ticks -= d;
|
||||
|
||||
ASSERTLINE(370, ticks % OSSecondsToTicks(1) == 0);
|
||||
ASSERTLINE(374, 0 <= OSTicksToSeconds(ticks) / 86400 + BIAS && OSTicksToSeconds(ticks) / 86400 + BIAS <= INT_MAX);
|
||||
|
||||
days = (OS_TICKS_TO_SEC(ticks) / SECS_IN_DAY) + BIAS;
|
||||
secs = OS_TICKS_TO_SEC(ticks) % SECS_IN_DAY;
|
||||
if (secs < 0) {
|
||||
days -= 1;
|
||||
secs += SECS_IN_DAY;
|
||||
ASSERTLINE(381, 0 <= secs);
|
||||
}
|
||||
|
||||
GetDates(days, td);
|
||||
td->hour = secs / 60 / 60;
|
||||
td->min = secs / 60 % 60;
|
||||
td->sec = secs % 60;
|
||||
}
|
||||
|
||||
OSTime OSCalendarTimeToTicks(OSCalendarTime* td) {
|
||||
OSTime secs;
|
||||
int ov_mon;
|
||||
int mon;
|
||||
int year;
|
||||
|
||||
ov_mon = td->mon / MONTH_MAX;
|
||||
mon = td->mon - (ov_mon * MONTH_MAX);
|
||||
|
||||
if (mon < 0) {
|
||||
mon += MONTH_MAX;
|
||||
ov_mon--;
|
||||
}
|
||||
|
||||
ASSERTLINE(412, (ov_mon <= 0 && 0 <= td->year + ov_mon) || (0 < ov_mon && td->year <= INT_MAX - ov_mon));
|
||||
|
||||
year = td->year + ov_mon;
|
||||
|
||||
secs = (OSTime)SECS_IN_YEAR * year +
|
||||
(OSTime)SECS_IN_DAY * (GetLeapDays(year) + GetYearDays(year, mon) + td->mday - 1) +
|
||||
(OSTime)SECS_IN_HOUR * td->hour +
|
||||
(OSTime)SECS_IN_MIN * td->min +
|
||||
td->sec -
|
||||
(OSTime)0xEB1E1BF80ULL;
|
||||
|
||||
return OS_SEC_TO_TICKS(secs) + OS_MSEC_TO_TICKS((OSTime)td->msec) +
|
||||
OS_USEC_TO_TICKS((OSTime)td->usec);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,150 @@
|
|||
#ifndef _REVOLUTION_OS_INTERNAL_H_
|
||||
#define _REVOLUTION_OS_INTERNAL_H_
|
||||
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/esp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// OS
|
||||
extern char* __OSExceptionNames[17]; // D ONLY
|
||||
|
||||
u32 __OSIsDebuggerPresent(void);
|
||||
void __OSPSInit(void);
|
||||
void __OSInitIPCBuffer(void);
|
||||
void __OSInitSTM(void);
|
||||
void __OSInitNet(void);
|
||||
void __OSInitPlayTime(void);
|
||||
void __OSStartPlayRecord(void);
|
||||
|
||||
// OSAlarm
|
||||
void __OSInitAlarm(void);
|
||||
void __OSCancelInternalAlarms(void* userdata);
|
||||
|
||||
// OSAlloc
|
||||
extern volatile int __OSCurrHeap;
|
||||
|
||||
// OSAudioSystem
|
||||
void __OSInitAudioSystem(void);
|
||||
void __OSStopAudioSystem(void);
|
||||
|
||||
// OSCache
|
||||
void __OSCacheInit(void);
|
||||
|
||||
// OSContext
|
||||
void __OSContextInit(void);
|
||||
|
||||
// OSError
|
||||
void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar);
|
||||
|
||||
// OSExec
|
||||
void __OSGetExecParams(OSExecParams* params);
|
||||
void __OSSetExecParams(const OSExecParams* params, OSExecParams* addr);
|
||||
void __OSBootDolSimple(u32 doloffset, u32 restartCode, void* regionStart, void* regionEnd, BOOL argsUseDefault, s32 argc, char** argv);
|
||||
void __OSBootDol(u32 doloffset, u32 restartCode, const char** argv);
|
||||
extern u32 __OSNextPartitionType;
|
||||
|
||||
// OSInterrupt
|
||||
extern void __RAS_OSDisableInterrupts_begin(void);
|
||||
extern void __RAS_OSDisableInterrupts_end(void);
|
||||
|
||||
extern u64 __OSSpuriousInterrupts; // D ONLY
|
||||
extern char* __OSInterruptNames[33]; // D ONLY
|
||||
extern char* __OSPIErrors[8]; // D ONLY
|
||||
|
||||
__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler);
|
||||
__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt);
|
||||
void __OSInterruptInit(void);
|
||||
OSInterruptMask __OSMaskInterrupts(OSInterruptMask global);
|
||||
OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask global);
|
||||
void __OSDispatchInterrupt(__OSException exception, OSContext* context);
|
||||
void __OSModuleInit(void);
|
||||
|
||||
// OSMemory
|
||||
void __OSInitMemoryProtection(void);
|
||||
|
||||
// OSMutex
|
||||
void __OSUnlockAllMutex(OSThread* thread);
|
||||
int __OSCheckDeadLock(OSThread* thread);
|
||||
int __OSCheckMutexes(OSThread* thread);
|
||||
|
||||
// OSPlayTime
|
||||
void __OSGetPlayTime(ESTicketView* ticket, __OSPlayTimeType* type, u32* playTime);
|
||||
|
||||
// OSReset
|
||||
void __OSDoHotReset(u32 resetCode);
|
||||
void __OSShutdownDevices(u32 event);
|
||||
int __OSCallShutdownFunctions(BOOL final, u32 event);
|
||||
|
||||
// OSResetSW
|
||||
void __OSResetSWInterruptHandler(s16 exception, OSContext* context);
|
||||
void __OSSetResetButtonTimer(u8 min);
|
||||
|
||||
// OSRtc
|
||||
int __OSGetRTC(u32* rtc);
|
||||
int __OSSetRTC(u32 rtc);
|
||||
void __OSInitSram(void);
|
||||
OSSram* __OSLockSram(void);
|
||||
OSSramEx* __OSLockSramEx(void);
|
||||
int __OSUnlockSram(BOOL commit);
|
||||
int __OSUnlockSramEx(BOOL commit);
|
||||
int __OSSyncSram(void);
|
||||
int __OSCheckSram(void);
|
||||
int __OSReadROM(void* buffer, s32 length, s32 offset);
|
||||
int __OSReadROMAsync(void* buffer, s32 length, s32 offset, void (*callback)());
|
||||
u8 __OSGetBootMode(void);
|
||||
void __OSSetBootMode(u8 ntd);
|
||||
|
||||
// OSSync
|
||||
extern void __OSSystemCallVectorStart();
|
||||
extern void __OSSystemCallVectorEnd();
|
||||
|
||||
void __OSInitSystemCall(void);
|
||||
|
||||
// OSThread
|
||||
void __OSThreadInit(void);
|
||||
s32 __OSGetEffectivePriority(OSThread* thread);
|
||||
void __OSPromoteThread(OSThread* thread, s32 priority);
|
||||
void __OSReschedule(void);
|
||||
|
||||
// OSTime
|
||||
void __OSSetTime(OSTime time);
|
||||
OSTime __OSGetSystemTime();
|
||||
void __OSSetTick(register OSTick newTicks);
|
||||
OSTime __OSTimeToSystemTime(OSTime time);
|
||||
|
||||
// ppc_eabi_init
|
||||
__declspec(section ".init") asm void __init_hardware(void);
|
||||
__declspec(section ".init") asm void __flush_cache(void* address, unsigned int size);
|
||||
void __init_user(void);
|
||||
void _ExitProcess(void);
|
||||
|
||||
// start
|
||||
__declspec(weak) void InitMetroTRK_BBA();
|
||||
|
||||
__declspec(section ".init") void __start(void);
|
||||
|
||||
__declspec(section ".init") extern void __start(void);
|
||||
__declspec(section ".init") void __copy_rom_section(void* dst, const void* src, u32 size);
|
||||
__declspec(section ".init") void __init_bss_section(void* dst, u32 size);
|
||||
__declspec(section ".init") extern void __init_registers(void);
|
||||
__declspec(section ".init") extern void __init_data(void);
|
||||
|
||||
// time.dolphin
|
||||
OSTime __get_clock(void);
|
||||
u32 __get_time(void);
|
||||
int __to_gm_time(void);
|
||||
|
||||
|
||||
// unsorted
|
||||
void __OSWriteExpiredFlag(void);
|
||||
void __OSReturnToMenuForError(void);
|
||||
void __OSHotResetForError(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _REVOLUTION_OS_INTERNAL_H_
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#include <revolution/base/PPCArch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void __init_cpp(void);
|
||||
void _ExitProcess(void);
|
||||
|
||||
typedef void (*voidfunctionptr)();
|
||||
extern voidfunctionptr _ctors[];
|
||||
extern voidfunctionptr _dtors[];
|
||||
|
||||
void __init_user(void) {
|
||||
__init_cpp();
|
||||
}
|
||||
|
||||
void __init_cpp(void) {
|
||||
/**
|
||||
* call static initializers
|
||||
*/
|
||||
voidfunctionptr* constructor;
|
||||
for (constructor = _ctors; *constructor; constructor++) {
|
||||
(*constructor)();
|
||||
}
|
||||
}
|
||||
|
||||
static void __fini_cpp(void) {
|
||||
voidfunctionptr* dtor;
|
||||
|
||||
for (dtor = _dtors; *dtor; dtor++) {
|
||||
(*dtor)();
|
||||
}
|
||||
}
|
||||
|
||||
void exit(int status) {
|
||||
__fini_cpp();
|
||||
_ExitProcess();
|
||||
}
|
||||
|
||||
void _ExitProcess(void) {
|
||||
PPCHalt();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Loading…
Reference in New Issue