shieldD revolution OS mostly done (#2892)

* begin revolution sdk setup

* wii rvl test

* revo OS mostly done for shieldD
This commit is contained in:
TakaRikka 2025-11-29 22:59:04 -08:00 committed by GitHub
parent 3c1323cf0d
commit 139722c731
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
59 changed files with 18747 additions and 100 deletions

View File

@ -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:

View File

@ -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),

View File

@ -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);

View File

@ -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

138
include/revolution/esp.h Normal file
View File

@ -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

View File

@ -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

167
include/revolution/nand.h Normal file
View File

@ -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

View File

@ -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) \

View File

@ -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
}

View File

@ -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);

View File

@ -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_

View File

@ -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
}

View File

@ -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);

View File

@ -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_

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -8,6 +8,7 @@ extern "C" {
#endif
typedef void (*OSResetCallback)(void);
typedef void (*OSPowerCallback)(void);
OSResetCallback OSSetResetCallback(OSResetCallback callback);
BOOL OSGetResetSwitchState(void);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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
}

View File

@ -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_

966
src/revolution/os/OS.c Normal file
View File

@ -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;
}

View File

@ -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);
}

324
src/revolution/os/OSAlarm.c Normal file
View File

@ -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;
}

608
src/revolution/os/OSAlloc.c Normal file
View File

@ -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);
}
}
}
}

View File

@ -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;
}

View File

@ -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
}

639
src/revolution/os/OSCache.c Normal file
View File

@ -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);
}

View File

@ -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

215
src/revolution/os/OSError.c Normal file
View File

@ -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();
}

795
src/revolution/os/OSExec.c Normal file
View File

@ -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");
}

256
src/revolution/os/OSFatal.c Normal file
View File

@ -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();
}

748
src/revolution/os/OSFont.c Normal file
View File

@ -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;
}

View File

@ -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

18
src/revolution/os/OSIpc.c Normal file
View File

@ -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);
}

View File

@ -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) {
}
}

537
src/revolution/os/OSLink.c Normal file
View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

256
src/revolution/os/OSMutex.c Normal file
View File

@ -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, &currentThread->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, &currentThread->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, &currentThread->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, &currentThread->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;
}

View File

@ -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;
}

300
src/revolution/os/OSNet.c Normal file
View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;
}

339
src/revolution/os/OSReset.c Normal file
View File

@ -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");
}

564
src/revolution/os/OSRtc.c Normal file
View File

@ -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;
}

View File

@ -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;
}

View File

@ -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) {
}
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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 != &currentThread->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(&currentThread->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(&currentThread->context);
if (currentThread->attr & 1) {
DEQUEUE_THREAD(currentThread, &__OSActiveThreadQueue, linkActive);
currentThread->state = 0;
} else {
currentThread->state = 8;
currentThread->val = val;
}
__OSUnlockAllMutex(currentThread);
OSWakeupThread(&currentThread->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);

201
src/revolution/os/OSTime.c Normal file
View File

@ -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);
}

6374
src/revolution/os/OSUtf.c Normal file

File diff suppressed because it is too large Load Diff

150
src/revolution/os/__os.h Normal file
View File

@ -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_

View File

@ -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