Release development version
This commit is contained in:
parent
bd01f31bfc
commit
0e018f8392
@ -1,13 +0,0 @@
|
|||||||
#ifndef TCPGECKO_BIT_UTILITIES_H
|
|
||||||
#define TCPGECKO_BIT_UTILITIES_H
|
|
||||||
|
|
||||||
// http://stackoverflow.com/a/47990/3764804
|
|
||||||
inline unsigned int setBit(unsigned int value, bool bit, int bitIndex) {
|
|
||||||
return value | (bit << bitIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool getBit(unsigned int value, int bitIndex) {
|
|
||||||
return ((value >> bitIndex) & 1) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,87 +0,0 @@
|
|||||||
#include "bit.h"
|
|
||||||
#include "stringify.h"
|
|
||||||
|
|
||||||
#ifndef TCPGECKO_BREAKPOINTS_H
|
|
||||||
#define TCPGECKO_BREAKPOINTS_H
|
|
||||||
|
|
||||||
/* Breakpoint types
|
|
||||||
#define BREAKPOINT_READ 0x01
|
|
||||||
#define BREAKPOINT_WRITE 0x02 */
|
|
||||||
|
|
||||||
struct DataBreakpoint {
|
|
||||||
unsigned int value;
|
|
||||||
bool translate;
|
|
||||||
bool write;
|
|
||||||
bool read;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
// Special purpose registers
|
|
||||||
#define INSTRUCTION_ADDRESS_BREAKPOINT_REGISTER 0x3F2
|
|
||||||
#define DATA_ADDRESS_BREAKPOINT_REGISTER 0x3F5
|
|
||||||
|
|
||||||
// Data address breakpoint bit indices
|
|
||||||
#define TRANSLATE_BIT_INDEX 29
|
|
||||||
#define WRITE_BIT_INDEX 30
|
|
||||||
#define READ_BIT_INDEX 31
|
|
||||||
|
|
||||||
// http://www.ds.ewi.tudelft.nl/vakken/in1006/instruction-set/mtspr.html
|
|
||||||
#define moveToSpecialPurposeRegister(specialPurposeRegister, value) \
|
|
||||||
__asm__ __volatile__ ("mtspr %0, %1" : : "K" (specialPurposeRegister), "r" (value)) \
|
|
||||||
|
|
||||||
// http://elixir.free-electrons.com/linux/v2.6.24/source/include/asm-powerpc/reg.h#L713
|
|
||||||
#define moveFromSpecialPurposeRegister(specialPurposeRegister) \
|
|
||||||
({unsigned int value; \
|
|
||||||
asm volatile("mfspr %0, " __stringify(specialPurposeRegister) : "=r" (value)); \
|
|
||||||
value;}) \
|
|
||||||
|
|
||||||
|
|
||||||
// https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.alangref/idalangref_isync_ics_instrs.htm
|
|
||||||
static inline void synchronizeInstructions() {
|
|
||||||
__asm__ __volatile__ ("isync" : : : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.alangref/idalangref_eieio_instrs.htm
|
|
||||||
static inline void enforeInOrderExecutionOfIO() {
|
|
||||||
__asm__ __volatile__ ("eieio" : : : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void setDataAddressBreakpointRegister(struct DataBreakpoint dataBreakpoint) {
|
|
||||||
unsigned int value = dataBreakpoint.value;
|
|
||||||
|
|
||||||
// Breakpoint translation
|
|
||||||
value = setBit(value, dataBreakpoint.translate, TRANSLATE_BIT_INDEX);
|
|
||||||
|
|
||||||
// Write breakpoint
|
|
||||||
value = setBit(value, dataBreakpoint.write, WRITE_BIT_INDEX);
|
|
||||||
|
|
||||||
// Read breakpoint
|
|
||||||
value = setBit(value, dataBreakpoint.read, READ_BIT_INDEX);
|
|
||||||
|
|
||||||
moveToSpecialPurposeRegister(DATA_ADDRESS_BREAKPOINT_REGISTER, value);
|
|
||||||
synchronizeInstructions();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct DataBreakpoint getDataAddressBreakpointRegisterContents(struct DataBreakpoint dataBreakpoint) {
|
|
||||||
unsigned int value = moveFromSpecialPurposeRegister(DATA_ADDRESS_BREAKPOINT_REGISTER);
|
|
||||||
dataBreakpoint.translate = getBit(value, TRANSLATE_BIT_INDEX);
|
|
||||||
dataBreakpoint.write = getBit(value, WRITE_BIT_INDEX);
|
|
||||||
dataBreakpoint.read = getBit(value, READ_BIT_INDEX);
|
|
||||||
value = setBit(value, 0, TRANSLATE_BIT_INDEX);
|
|
||||||
value = setBit(value, 0, WRITE_BIT_INDEX);
|
|
||||||
value = setBit(value, 0, READ_BIT_INDEX);
|
|
||||||
dataBreakpoint.value = value;
|
|
||||||
|
|
||||||
return dataBreakpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.manualslib.com/manual/606065/Ibm-Powerpc-750gx.html?page=64
|
|
||||||
static inline void setInstructionAddressBreakpointRegister(unsigned int address) {
|
|
||||||
moveToSpecialPurposeRegister(INSTRUCTION_ADDRESS_BREAKPOINT_REGISTER, address);
|
|
||||||
synchronizeInstructions();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int getInstructionAddressBreakpointRegister() {
|
|
||||||
return moveFromSpecialPurposeRegister(INSTRUCTION_ADDRESS_BREAKPOINT_REGISTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,8 +0,0 @@
|
|||||||
#ifndef TCPGECKO_STRING_H
|
|
||||||
#define TCPGECKO_STRING_H
|
|
||||||
|
|
||||||
// http://elixir.free-electrons.com/linux/v2.6.24/source/include/linux/stringify.h#L9
|
|
||||||
#define __stringify_1(x) #x
|
|
||||||
#define __stringify(x) __stringify_1(x)
|
|
||||||
|
|
||||||
#endif
|
|
@ -52,6 +52,20 @@ EXPORT_DECL(int, OSCreateThread, void *thread, s32(*callback)(s32, void * ), s32
|
|||||||
priority, u32
|
priority, u32
|
||||||
attr);
|
attr);
|
||||||
|
|
||||||
|
EXPORT_DECL(void, OSEnableInterrupts, void);
|
||||||
|
|
||||||
|
EXPORT_DECL(void, __OSClearAndEnableInterrupt, void);
|
||||||
|
|
||||||
|
EXPORT_DECL(int, OSIsInterruptEnabled, void);
|
||||||
|
|
||||||
|
EXPORT_DECL(int, OSIsDebuggerPresent, void);
|
||||||
|
|
||||||
|
EXPORT_DECL(void, OSRestoreInterrupts, void);
|
||||||
|
|
||||||
|
EXPORT_DECL(void, OSSetDABR, int, int, int, int);
|
||||||
|
|
||||||
|
EXPORT_DECL(void, OSSetIABR, int, int);
|
||||||
|
|
||||||
EXPORT_DECL(int, OSGetCurrentThread, void);
|
EXPORT_DECL(int, OSGetCurrentThread, void);
|
||||||
|
|
||||||
EXPORT_DECL(int, OSResumeThread, void *thread);
|
EXPORT_DECL(int, OSResumeThread, void *thread);
|
||||||
@ -103,8 +117,9 @@ EXPORT_DECL(void, __Exit, void);
|
|||||||
|
|
||||||
EXPORT_DECL(void, OSFatal, const char *msg);
|
EXPORT_DECL(void, OSFatal, const char *msg);
|
||||||
|
|
||||||
EXPORT_DECL(void, OSSetExceptionCallback, u8
|
EXPORT_DECL(void, OSSetExceptionCallback, u8 exceptionType, exception_callback callback);
|
||||||
exceptionType, exception_callback newCallback);
|
|
||||||
|
EXPORT_DECL(void, __OSSetInterruptHandler, u8 exceptionType, exception_callback callback);
|
||||||
|
|
||||||
EXPORT_DECL(void, DCFlushRange, const void *addr, u32
|
EXPORT_DECL(void, DCFlushRange, const void *addr, u32
|
||||||
length);
|
length);
|
||||||
@ -250,6 +265,7 @@ void InitOSFunctionPointers(void) {
|
|||||||
OS_FIND_EXPORT(coreinit_handle, OSFatal);
|
OS_FIND_EXPORT(coreinit_handle, OSFatal);
|
||||||
OS_FIND_EXPORT(coreinit_handle, OSGetTitleID);
|
OS_FIND_EXPORT(coreinit_handle, OSGetTitleID);
|
||||||
OS_FIND_EXPORT(coreinit_handle, OSSetExceptionCallback);
|
OS_FIND_EXPORT(coreinit_handle, OSSetExceptionCallback);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, __OSSetInterruptHandler);
|
||||||
OS_FIND_EXPORT(coreinit_handle, DCFlushRange);
|
OS_FIND_EXPORT(coreinit_handle, DCFlushRange);
|
||||||
OS_FIND_EXPORT(coreinit_handle, ICInvalidateRange);
|
OS_FIND_EXPORT(coreinit_handle, ICInvalidateRange);
|
||||||
OS_FIND_EXPORT(coreinit_handle, OSEffectiveToPhysical);
|
OS_FIND_EXPORT(coreinit_handle, OSEffectiveToPhysical);
|
||||||
@ -279,6 +295,13 @@ void InitOSFunctionPointers(void) {
|
|||||||
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
//! Thread functions
|
//! Thread functions
|
||||||
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, OSEnableInterrupts);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, __OSClearAndEnableInterrupt);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, OSIsInterruptEnabled);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, OSIsDebuggerPresent);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, OSRestoreInterrupts);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, OSSetDABR);
|
||||||
|
OS_FIND_EXPORT(coreinit_handle, OSSetIABR);
|
||||||
OS_FIND_EXPORT(coreinit_handle, OSGetCurrentThread);
|
OS_FIND_EXPORT(coreinit_handle, OSGetCurrentThread);
|
||||||
OS_FIND_EXPORT(coreinit_handle, OSCreateThread);
|
OS_FIND_EXPORT(coreinit_handle, OSCreateThread);
|
||||||
OS_FIND_EXPORT(coreinit_handle, OSResumeThread);
|
OS_FIND_EXPORT(coreinit_handle, OSResumeThread);
|
||||||
|
@ -140,6 +140,20 @@ extern int
|
|||||||
(*OSCreateThread)(void *thread, s32 (*callback)(s32, void *), s32 argc, void *args, u32 stack, u32 stack_size,
|
(*OSCreateThread)(void *thread, s32 (*callback)(s32, void *), s32 argc, void *args, u32 stack, u32 stack_size,
|
||||||
s32 priority, u32 attr);
|
s32 priority, u32 attr);
|
||||||
|
|
||||||
|
extern void (*OSEnableInterrupts)(void);
|
||||||
|
|
||||||
|
extern void (*__OSClearAndEnableInterrupt)(void);
|
||||||
|
|
||||||
|
extern int (*OSIsInterruptEnabled)(void);
|
||||||
|
|
||||||
|
extern int (*OSIsDebuggerPresent)(void);
|
||||||
|
|
||||||
|
extern void (*OSRestoreInterrupts)(void);
|
||||||
|
|
||||||
|
extern void (*OSSetDABR)(int, int, int, int);
|
||||||
|
|
||||||
|
extern void (*OSSetIABR)(int, int);
|
||||||
|
|
||||||
extern int (*OSGetCurrentThread)(void);
|
extern int (*OSGetCurrentThread)(void);
|
||||||
|
|
||||||
extern int (*OSResumeThread)(void *thread);
|
extern int (*OSResumeThread)(void *thread);
|
||||||
@ -216,7 +230,9 @@ extern int (*OSScreenEnableEx)(unsigned int bufferNum, int enable);
|
|||||||
|
|
||||||
typedef unsigned char (*exception_callback)(void *interruptedContext);
|
typedef unsigned char (*exception_callback)(void *interruptedContext);
|
||||||
|
|
||||||
extern void (*OSSetExceptionCallback)(u8 exceptionType, exception_callback newCallback);
|
extern void (*OSSetExceptionCallback)(u8 exceptionType, exception_callback callback);
|
||||||
|
|
||||||
|
extern void (*__OSSetInterruptHandler)(u8 interruptType, exception_callback callback);
|
||||||
|
|
||||||
extern int (*OSAllocFromSystem)(unsigned int size, unsigned int align);
|
extern int (*OSAllocFromSystem)(unsigned int size, unsigned int align);
|
||||||
|
|
||||||
|
19
src/entry.c
19
src/entry.c
@ -5,25 +5,10 @@
|
|||||||
#include "pygecko.h"
|
#include "pygecko.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
|
#include "title.h"
|
||||||
#define TITLE_ID_MII_VERSE 0x000500301001600A
|
|
||||||
#define TITLE_ID_MII_MAKER 0x000500101004A000
|
|
||||||
#define TITLE_ID_BAYONETTA_2 0x0005000010172500
|
|
||||||
#define TITLE_ID_INTERNET_BROWSER 0x000500301001200A
|
|
||||||
|
|
||||||
bool isRunningTitleID(unsigned long long int japaneseTitleID) {
|
|
||||||
unsigned long long int currentTitleID = (unsigned long long int) OSGetTitleID();
|
|
||||||
return currentTitleID == japaneseTitleID // JAP
|
|
||||||
|| currentTitleID == japaneseTitleID + 0x100 // USA
|
|
||||||
|| currentTitleID == japaneseTitleID + 0x200; // EUR
|
|
||||||
}
|
|
||||||
|
|
||||||
int __entry_menu(int argc, char **argv) {
|
int __entry_menu(int argc, char **argv) {
|
||||||
if (OSGetTitleID != 0
|
if (isRunningAllowedTitleID()) {
|
||||||
&& !isRunningTitleID(TITLE_ID_MII_VERSE)
|
|
||||||
&& !isRunningTitleID(TITLE_ID_MII_MAKER)
|
|
||||||
&& !isRunningTitleID(TITLE_ID_BAYONETTA_2)
|
|
||||||
&& !isRunningTitleID(TITLE_ID_INTERNET_BROWSER)) {
|
|
||||||
InitOSFunctionPointers();
|
InitOSFunctionPointers();
|
||||||
InitSocketFunctionPointers();
|
InitSocketFunctionPointers();
|
||||||
InitGX2FunctionPointers();
|
InitGX2FunctionPointers();
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#ifndef TCPGECKO_ENTRY_H
|
|
||||||
#define TCPGECKO_ENTRY_H
|
|
||||||
|
|
||||||
bool isRunningTitleID(unsigned long long int japaneseTitleID);
|
|
||||||
|
|
||||||
#endif
|
|
@ -7,19 +7,24 @@ extern "C" {
|
|||||||
|
|
||||||
#include <gctypes.h>
|
#include <gctypes.h>
|
||||||
#include "common/kernel_defs.h"
|
#include "common/kernel_defs.h"
|
||||||
|
#include "../common/kernel_defs.h"
|
||||||
|
|
||||||
void KernelSetupSyscalls(void);
|
void KernelSetupSyscalls(void);
|
||||||
|
|
||||||
void KernelRestoreInstructions(void);
|
void KernelRestoreInstructions(void);
|
||||||
|
|
||||||
void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len);
|
void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len);
|
||||||
|
|
||||||
void SC0x36_KernelReadDBATs(bat_table_t *table);
|
void SC0x36_KernelReadDBATs(bat_table_t *table);
|
||||||
|
|
||||||
void SC0x37_KernelWriteDBATs(bat_table_t *table);
|
void SC0x37_KernelWriteDBATs(bat_table_t *table);
|
||||||
|
|
||||||
uint32_t __attribute__ ((noinline)) kern_read(const void *addr);
|
uint32_t __attribute__ ((noinline)) kern_read(const void *addr);
|
||||||
|
|
||||||
void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value);
|
void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // __KERNEL_FUNCTIONS_H_
|
#endif
|
369
src/pygecko.c
369
src/pygecko.c
@ -15,7 +15,13 @@
|
|||||||
#include "system/exception_handler.h"
|
#include "system/exception_handler.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
#include "system/memory.h"
|
#include "system/memory.h"
|
||||||
#include "breakpoints/breakpoints.h"
|
#include "system/breakpoints.h"
|
||||||
|
#include "system/threads.h"
|
||||||
|
#include "utils/linked_list.h"
|
||||||
|
#include "assertions.h"
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "address.h"
|
||||||
|
#include "disassembler.h"
|
||||||
|
|
||||||
void *client;
|
void *client;
|
||||||
void *commandBlock;
|
void *commandBlock;
|
||||||
@ -48,12 +54,11 @@ struct pygecko_bss_t {
|
|||||||
#define COMMAND_GET_CODE_HANDLER_ADDRESS 0x55
|
#define COMMAND_GET_CODE_HANDLER_ADDRESS 0x55
|
||||||
#define COMMAND_READ_THREADS 0x56
|
#define COMMAND_READ_THREADS 0x56
|
||||||
#define COMMAND_ACCOUNT_IDENTIFIER 0x57
|
#define COMMAND_ACCOUNT_IDENTIFIER 0x57
|
||||||
#define COMMAND_WRITE_SCREEN 0x58 // TODO Exception DSI
|
// #define COMMAND_WRITE_SCREEN 0x58 // TODO Exception DSI
|
||||||
#define COMMAND_FOLLOW_POINTER 0x60
|
#define COMMAND_FOLLOW_POINTER 0x60
|
||||||
#define COMMAND_REMOTE_PROCEDURE_CALL 0x70
|
#define COMMAND_REMOTE_PROCEDURE_CALL 0x70
|
||||||
#define COMMAND_GET_SYMBOL 0x71
|
#define COMMAND_GET_SYMBOL 0x71
|
||||||
#define COMMAND_MEMORY_SEARCH 0x73
|
#define COMMAND_MEMORY_SEARCH 0x73
|
||||||
// #define COMMAND_SYSTEM_CALL 0x80
|
|
||||||
#define COMMAND_EXECUTE_ASSEMBLY 0x81
|
#define COMMAND_EXECUTE_ASSEMBLY 0x81
|
||||||
#define COMMAND_PAUSE_CONSOLE 0x82
|
#define COMMAND_PAUSE_CONSOLE 0x82
|
||||||
#define COMMAND_RESUME_CONSOLE 0x83
|
#define COMMAND_RESUME_CONSOLE 0x83
|
||||||
@ -61,74 +66,23 @@ struct pygecko_bss_t {
|
|||||||
#define COMMAND_SERVER_VERSION 0x99
|
#define COMMAND_SERVER_VERSION 0x99
|
||||||
#define COMMAND_GET_OS_VERSION 0x9A
|
#define COMMAND_GET_OS_VERSION 0x9A
|
||||||
#define COMMAND_SET_DATA_BREAKPOINT 0xA0
|
#define COMMAND_SET_DATA_BREAKPOINT 0xA0
|
||||||
#define COMMAND_GET_DATA_BREAKPOINT 0xA1
|
|
||||||
#define COMMAND_SET_INSTRUCTION_BREAKPOINT 0xA2
|
#define COMMAND_SET_INSTRUCTION_BREAKPOINT 0xA2
|
||||||
#define COMMAND_GET_INSTRUCTION_BREAKPOINT 0xA3
|
|
||||||
#define COMMAND_RUN_KERNEL_COPY_SERVICE 0xCD
|
#define COMMAND_RUN_KERNEL_COPY_SERVICE 0xCD
|
||||||
#define COMMAND_IOSUHAX_READ_FILE 0xD0
|
#define COMMAND_IOSU_HAX_READ_FILE 0xD0
|
||||||
#define COMMAND_GET_VERSION_HASH 0xE0
|
#define COMMAND_GET_VERSION_HASH 0xE0
|
||||||
|
|
||||||
#define CHECK_ERROR(cond) if (cond) { bss->line = __LINE__; goto error; }
|
#define CHECK_ERROR(cond) if (cond) { bss->line = __LINE__; goto error; }
|
||||||
#define errno (*__gh_errno_ptr())
|
#define errno (*__gh_errno_ptr())
|
||||||
#define MSG_DONTWAIT 32
|
#define MSG_DONT_WAIT 32
|
||||||
#define EWOULDBLOCK 6
|
#define EWOULDBLOCK 6
|
||||||
#define DATA_BUFFER_SIZE 0x5000
|
#define DATA_BUFFER_SIZE 0x5000
|
||||||
#define WRITE_SCREEN_MESSAGE_BUFFER_SIZE 100
|
// #define WRITE_SCREEN_MESSAGE_BUFFER_SIZE 100
|
||||||
#define SERVER_VERSION "05/24/2017"
|
#define SERVER_VERSION "05/24/2017"
|
||||||
#define ONLY_ZEROS_READ 0xB0
|
#define ONLY_ZEROS_READ 0xB0
|
||||||
#define NON_ZEROS_READ 0xBD
|
#define NON_ZEROS_READ 0xBD
|
||||||
|
|
||||||
#define VERSION_HASH 0x39C9444B
|
#define VERSION_HASH 0x39C9444B
|
||||||
|
|
||||||
#define ASSERT_MINIMUM_HOLDS(actual, minimum, variableName) \
|
|
||||||
if(actual < minimum) { \
|
|
||||||
char buffer[100] = {0}; \
|
|
||||||
__os_snprintf(buffer, 100, "%s: Limit exceeded (minimum: %i, actual: %i)", variableName, minimum, actual); \
|
|
||||||
OSFatal(buffer); \
|
|
||||||
} \
|
|
||||||
|
|
||||||
#define ASSERT_MAXIMUM_HOLDS(maximum, actual, variableName) \
|
|
||||||
if(actual > maximum) { \
|
|
||||||
char buffer[100] = {0}; \
|
|
||||||
__os_snprintf(buffer, 100, "%s: Limit exceeded (maximum: %i, actual: %i)", variableName, maximum, actual); \
|
|
||||||
OSFatal(buffer); \
|
|
||||||
} \
|
|
||||||
|
|
||||||
#define ASSERT_FUNCTION_SUCCEEDED(returnValue, functionName) \
|
|
||||||
if (returnValue < 0) { \
|
|
||||||
char buffer[100] = {0}; \
|
|
||||||
__os_snprintf(buffer, 100, "%s failed with return value: %i", functionName, returnValue); \
|
|
||||||
OSFatal(buffer); \
|
|
||||||
} \
|
|
||||||
|
|
||||||
#define ASSERT_VALID_EFFECTIVE_ADDRESS(effectiveAddress, message) \
|
|
||||||
if(!OSIsAddressValid((void *) effectiveAddress)) { \
|
|
||||||
char buffer[100] = {0}; \
|
|
||||||
__os_snprintf(buffer, 100, "Address %04x invalid: %s", effectiveAddress, message); \
|
|
||||||
OSFatal(buffer); \
|
|
||||||
} \
|
|
||||||
|
|
||||||
#define ASSERT_INTEGER(actual, expected, name) \
|
|
||||||
if(actual != expected) { \
|
|
||||||
char buffer[50] = {0}; \
|
|
||||||
__os_snprintf(buffer, 50, "%s assertion failed: %i == %i", name, actual, expected); \
|
|
||||||
OSFatal(buffer); \
|
|
||||||
} \
|
|
||||||
|
|
||||||
#define ASSERT_STRING(actual, expected) \
|
|
||||||
if(strcmp(actual, expected) != 0) { \
|
|
||||||
char buffer[50] = {0}; \
|
|
||||||
__os_snprintf(buffer, 50, "String assertion failed: \"%s\" == \"%s\"", actual, expected); \
|
|
||||||
OSFatal(buffer); \
|
|
||||||
} \
|
|
||||||
|
|
||||||
#define ASSERT_ALLOCATED(variable, name) \
|
|
||||||
if(variable == 0) { \
|
|
||||||
char buffer[50] = {0}; \
|
|
||||||
__os_snprintf(buffer, 50, "%s allocation failed", name); \
|
|
||||||
OSFatal(buffer); \
|
|
||||||
} \
|
|
||||||
|
|
||||||
ZEXTERN int ZEXPORT
|
ZEXTERN int ZEXPORT
|
||||||
deflateEnd OF((z_streamp
|
deflateEnd OF((z_streamp
|
||||||
strm));
|
strm));
|
||||||
@ -143,75 +97,20 @@ strm,
|
|||||||
int flush
|
int flush
|
||||||
));
|
));
|
||||||
|
|
||||||
/*struct breakpoint {
|
// ########## Being kernel_copy.h ############
|
||||||
u32 address;
|
|
||||||
u32 instruction;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 10 general breakpoints + 2 step breakpoints
|
|
||||||
breakpoint breakpoints[12];
|
|
||||||
|
|
||||||
breakpoint *getBreakpoint(u32 address, int size) {
|
|
||||||
breakpoint *breakpointsList = breakpoints;
|
|
||||||
for (int breakpointIndex = 0; breakpointIndex < size; breakpointIndex++) {
|
|
||||||
if (breakpointsList[breakpointIndex].address == address) {
|
|
||||||
return &breakpointsList[breakpointIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
// TODO Variable size, not hard-coded
|
||||||
unsigned char *memcpy_buffer[DATA_BUFFER_SIZE];
|
unsigned char *memcpy_buffer[DATA_BUFFER_SIZE];
|
||||||
|
|
||||||
void pygecko_memcpy(unsigned char *destinationBuffer, unsigned char *sourceBuffer, unsigned int length) {
|
void pygecko_memcpy(unsigned char *destinationBuffer, unsigned char *sourceBuffer, unsigned int length) {
|
||||||
memcpy(memcpy_buffer, sourceBuffer, length);
|
memcpy(memcpy_buffer, sourceBuffer, length);
|
||||||
SC0x25_KernelCopyData((unsigned int) OSEffectiveToPhysical(destinationBuffer), (unsigned int) &memcpy_buffer,
|
SC0x25_KernelCopyData((unsigned int) OSEffectiveToPhysical(destinationBuffer), (unsigned int) &memcpy_buffer, length);
|
||||||
length);
|
|
||||||
DCFlushRange(destinationBuffer, (u32) length);
|
DCFlushRange(destinationBuffer, (u32) length);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *kernelCopyBuffer[4];
|
// ########## End kernel_copy.h ############
|
||||||
|
|
||||||
void kernelCopy(unsigned char *destinationBuffer, unsigned char *sourceBuffer, unsigned int length) {
|
// ########## Being pause.h ############
|
||||||
memcpy(kernelCopyBuffer, sourceBuffer, length);
|
|
||||||
unsigned int destinationAddress = (unsigned int) OSEffectiveToPhysical(destinationBuffer);
|
|
||||||
SC0x25_KernelCopyData(destinationAddress, (unsigned int) &kernelCopyBuffer, length);
|
|
||||||
DCFlushRange(destinationBuffer, (u32) length);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define KERNEL_COPY_SOURCE_ADDRESS 0x10100000
|
|
||||||
|
|
||||||
int kernelCopyService(int argc, void *argv) {
|
|
||||||
while (true) {
|
|
||||||
// Read the destination address from the source address
|
|
||||||
int destinationAddress = *(int *) KERNEL_COPY_SOURCE_ADDRESS;
|
|
||||||
|
|
||||||
// Avoid crashing
|
|
||||||
if (OSIsAddressValid((const void *) destinationAddress)) {
|
|
||||||
// Perform memory copy
|
|
||||||
unsigned char *valueBuffer = (unsigned char *) (KERNEL_COPY_SOURCE_ADDRESS + 4);
|
|
||||||
kernelCopy((unsigned char *) destinationAddress, valueBuffer, 4);
|
|
||||||
|
|
||||||
// "Consume" address and value for synchronization with the code handler for instance
|
|
||||||
*(int *) KERNEL_COPY_SOURCE_ADDRESS = 0;
|
|
||||||
*(((int *) KERNEL_COPY_SOURCE_ADDRESS) + 1) = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void startKernelCopyService() {
|
|
||||||
unsigned int stack = (unsigned int) memalign(0x40, 0x100);
|
|
||||||
ASSERT_ALLOCATED(stack, "Kernel copy thread stack")
|
|
||||||
stack += 0x100;
|
|
||||||
void *thread = memalign(0x40, 0x1000);
|
|
||||||
ASSERT_ALLOCATED(thread, "Kernel copy thread")
|
|
||||||
|
|
||||||
int status = OSCreateThread(thread, kernelCopyService, 1, NULL, (u32) stack + sizeof(stack), sizeof(stack), 31,
|
|
||||||
OS_THREAD_ATTR_AFFINITY_CORE1 | OS_THREAD_ATTR_PINNED_AFFINITY | OS_THREAD_ATTR_DETACH);
|
|
||||||
ASSERT_INTEGER(status, 1, "Creating kernel copy thread")
|
|
||||||
// OSSetThreadName(thread, "Kernel Copier");
|
|
||||||
OSResumeThread(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
int (*AVMGetDRCScanMode)(int);
|
int (*AVMGetDRCScanMode)(int);
|
||||||
|
|
||||||
@ -255,10 +154,9 @@ bool isConsolePaused() {
|
|||||||
return value == PAUSED;
|
return value == PAUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Validates the address range (last address inclusive) but is SLOW on bigger ranges */
|
// ########## End pause.h ############
|
||||||
static int validateAddressRange(int starting_address, int ending_address) {
|
|
||||||
return __OSValidateAddressSpaceRange(1, (void *) starting_address, ending_address - starting_address + 1);
|
// ########## Being socket_functions.h ############
|
||||||
}
|
|
||||||
|
|
||||||
static int recvwait(struct pygecko_bss_t *bss, int sock, void *buffer, int len) {
|
static int recvwait(struct pygecko_bss_t *bss, int sock, void *buffer, int len) {
|
||||||
int ret;
|
int ret;
|
||||||
@ -288,7 +186,7 @@ static int checkbyte(int sock) {
|
|||||||
unsigned char buffer[1];
|
unsigned char buffer[1];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = recv(sock, buffer, 1, MSG_DONTWAIT);
|
ret = recv(sock, buffer, 1, MSG_DONT_WAIT);
|
||||||
if (ret < 0) return ret;
|
if (ret < 0) return ret;
|
||||||
if (ret == 0) return -1;
|
if (ret == 0) return -1;
|
||||||
return buffer[0];
|
return buffer[0];
|
||||||
@ -315,32 +213,6 @@ static int sendByte(struct pygecko_bss_t *bss, int sock, unsigned char byte) {
|
|||||||
return sendwait(bss, sock, buffer, 1);
|
return sendwait(bss, sock, buffer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void performSystemCall(int value) {
|
|
||||||
// TODO Exception DSI?
|
|
||||||
asm(
|
|
||||||
"li 0, %0\n"
|
|
||||||
"sc\n"
|
|
||||||
"blr\n"
|
|
||||||
: // No output
|
|
||||||
:"r"(value) // Input
|
|
||||||
:"0" // Overwritten register
|
|
||||||
);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void writeScreen(char message[100], int secondsDelay) {
|
|
||||||
// TODO Does nothing then crashes (in games)?
|
|
||||||
OSScreenClearBufferEx(0, 0);
|
|
||||||
OSScreenClearBufferEx(1, 0);
|
|
||||||
|
|
||||||
OSScreenPutFontEx(0, 14, 1, message);
|
|
||||||
OSScreenPutFontEx(1, 14, 1, message);
|
|
||||||
|
|
||||||
sleep(secondsDelay);
|
|
||||||
|
|
||||||
OSScreenFlipBuffersEx(0);
|
|
||||||
OSScreenFlipBuffersEx(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void receiveString(struct pygecko_bss_t *bss,
|
void receiveString(struct pygecko_bss_t *bss,
|
||||||
int clientfd,
|
int clientfd,
|
||||||
char *stringBuffer,
|
char *stringBuffer,
|
||||||
@ -360,6 +232,22 @@ void receiveString(struct pygecko_bss_t *bss,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ########## End socket_functions.h ############
|
||||||
|
|
||||||
|
/*void writeScreen(char message[100], int secondsDelay) {
|
||||||
|
// TODO Does nothing then crashes (in games)?
|
||||||
|
OSScreenClearBufferEx(0, 0);
|
||||||
|
OSScreenClearBufferEx(1, 0);
|
||||||
|
|
||||||
|
OSScreenPutFontEx(0, 14, 1, message);
|
||||||
|
OSScreenPutFontEx(1, 14, 1, message);
|
||||||
|
|
||||||
|
sleep(secondsDelay);
|
||||||
|
|
||||||
|
OSScreenFlipBuffersEx(0);
|
||||||
|
OSScreenFlipBuffersEx(1);
|
||||||
|
}*/
|
||||||
|
|
||||||
void considerInitializingFileSystem() {
|
void considerInitializingFileSystem() {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
// Initialize the file system
|
// Initialize the file system
|
||||||
@ -382,45 +270,6 @@ void considerInitializingFileSystem() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *disassemblerBuffer;
|
|
||||||
void *disassemblerBufferPointer;
|
|
||||||
#define DISASSEMBLER_BUFFER_SIZE 0x1024
|
|
||||||
|
|
||||||
void formatDisassembled(char *format, ...) {
|
|
||||||
if (!disassemblerBuffer) {
|
|
||||||
disassemblerBuffer = malloc(DISASSEMBLER_BUFFER_SIZE);
|
|
||||||
ASSERT_ALLOCATED(disassemblerBuffer, "Disassembler buffer")
|
|
||||||
disassemblerBufferPointer = disassemblerBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_list variableArguments;
|
|
||||||
va_start(variableArguments, format);
|
|
||||||
char *temporaryBuffer;
|
|
||||||
int printedBytesCount = vasprintf(&temporaryBuffer, format, variableArguments);
|
|
||||||
ASSERT_ALLOCATED(temporaryBuffer, "Temporary buffer")
|
|
||||||
ASSERT_MINIMUM_HOLDS(printedBytesCount, 1, "Printed bytes count")
|
|
||||||
va_end(variableArguments);
|
|
||||||
|
|
||||||
// Do not smash the buffer
|
|
||||||
long projectedSize = (void *) disassemblerBuffer - disassemblerBufferPointer + printedBytesCount;
|
|
||||||
if (projectedSize < DISASSEMBLER_BUFFER_SIZE) {
|
|
||||||
memcpy(disassemblerBuffer, temporaryBuffer, printedBytesCount);
|
|
||||||
disassemblerBuffer += printedBytesCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(temporaryBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValidDataAddress(int address) {
|
|
||||||
return OSIsAddressValid((const void *) address)
|
|
||||||
&& address >= 0x10000000
|
|
||||||
&& address < 0x50000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
int roundUpToAligned(int number) {
|
|
||||||
return (number + 3) & ~0x03;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ERROR_BUFFER_SIZE 150
|
#define ERROR_BUFFER_SIZE 150
|
||||||
|
|
||||||
void reportIllegalCommandByte(int commandByte) {
|
void reportIllegalCommandByte(int commandByte) {
|
||||||
@ -431,37 +280,6 @@ void reportIllegalCommandByte(int commandByte) {
|
|||||||
OSFatal(errorBuffer);
|
OSFatal(errorBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MINIMUM_KERNEL_COMPARE_LENGTH 4
|
|
||||||
#define KERNEL_MEMORY_COMPARE_STEP_SIZE 1
|
|
||||||
|
|
||||||
int kernelMemoryCompare(const void *sourceBuffer,
|
|
||||||
const void *destinationBuffer,
|
|
||||||
int length) {
|
|
||||||
if (length < MINIMUM_KERNEL_COMPARE_LENGTH) {
|
|
||||||
ASSERT_MINIMUM_HOLDS(length, MINIMUM_KERNEL_COMPARE_LENGTH, "length");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loopEntered = false;
|
|
||||||
|
|
||||||
while (kern_read(sourceBuffer) == kern_read(destinationBuffer)) {
|
|
||||||
loopEntered = true;
|
|
||||||
sourceBuffer = (char *) sourceBuffer + KERNEL_MEMORY_COMPARE_STEP_SIZE;
|
|
||||||
destinationBuffer = (char *) destinationBuffer + KERNEL_MEMORY_COMPARE_STEP_SIZE;
|
|
||||||
length -= KERNEL_MEMORY_COMPARE_STEP_SIZE;
|
|
||||||
|
|
||||||
if (length <= MINIMUM_KERNEL_COMPARE_LENGTH - 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loopEntered) {
|
|
||||||
sourceBuffer -= KERNEL_MEMORY_COMPARE_STEP_SIZE;
|
|
||||||
destinationBuffer -= KERNEL_MEMORY_COMPARE_STEP_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return kern_read(sourceBuffer) - kern_read(destinationBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -1043,7 +861,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMMAND_IOSUHAX_READ_FILE: {
|
case COMMAND_IOSU_HAX_READ_FILE: {
|
||||||
log_print("COMMAND_IOSUHAX_READ_FILE");
|
log_print("COMMAND_IOSUHAX_READ_FILE");
|
||||||
|
|
||||||
// TODO Crashes console on this call
|
// TODO Crashes console on this call
|
||||||
@ -1139,43 +957,31 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMMAND_READ_THREADS: {
|
case COMMAND_READ_THREADS: {
|
||||||
int OS_THREAD_SIZE = 0x6A0;
|
struct node *threads = getAllThreads();
|
||||||
|
int threadCount = length(threads);
|
||||||
|
log_printf("Thread Count: %i\n", threadCount);
|
||||||
|
|
||||||
int currentThreadAddress = OSGetCurrentThread();
|
// Send the thread count
|
||||||
ASSERT_VALID_EFFECTIVE_ADDRESS(currentThreadAddress, "OSGetCurrentThread")
|
log_print("Sending thread count...\n");
|
||||||
int iterationThreadAddress = currentThreadAddress;
|
((int *) buffer)[0] = threadCount;
|
||||||
int temporaryThreadAddress;
|
ret = sendwait(bss, clientfd, buffer, sizeof(int));
|
||||||
|
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (thread count)");
|
||||||
|
|
||||||
// Follow "previous thread" pointers back to the beginning
|
// Send the thread addresses and data
|
||||||
while ((temporaryThreadAddress = *(int *) (iterationThreadAddress + 0x390)) != 0) {
|
struct node* currentThread = threads;
|
||||||
iterationThreadAddress = temporaryThreadAddress;
|
while (currentThread != NULL) {
|
||||||
ASSERT_VALID_EFFECTIVE_ADDRESS(iterationThreadAddress, "iterationThreadAddress going backwards")
|
int data = (int) currentThread->data;
|
||||||
|
log_printf("Thread data: %08x\n", data);
|
||||||
|
((int *) buffer)[0] = (int) currentThread->data;
|
||||||
|
memcpy(buffer + sizeof(int), currentThread->data, THREAD_SIZE);
|
||||||
|
log_print("Sending node...\n");
|
||||||
|
ret = sendwait(bss, clientfd, buffer, sizeof(int) + THREAD_SIZE);
|
||||||
|
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (thread address and data)")
|
||||||
|
|
||||||
|
currentThread = currentThread->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send all threads by following the "next thread" pointers
|
destroy(threads);
|
||||||
while ((temporaryThreadAddress = *(int *) (iterationThreadAddress + 0x38C)) != 0) {
|
|
||||||
// Send the starting thread's address
|
|
||||||
((int *) buffer)[0] = iterationThreadAddress;
|
|
||||||
|
|
||||||
// Send the thread struct itself
|
|
||||||
memcpy(buffer + 4, (void *) iterationThreadAddress, OS_THREAD_SIZE);
|
|
||||||
ret = sendwait(bss, clientfd, buffer, 4 + OS_THREAD_SIZE);
|
|
||||||
CHECK_ERROR(ret < 0)
|
|
||||||
|
|
||||||
iterationThreadAddress = temporaryThreadAddress;
|
|
||||||
ASSERT_VALID_EFFECTIVE_ADDRESS(iterationThreadAddress, "iterationThreadAddress going forwards")
|
|
||||||
}
|
|
||||||
|
|
||||||
// The previous while would skip the last thread so send it also
|
|
||||||
((int *) buffer)[0] = iterationThreadAddress;
|
|
||||||
memcpy(buffer + 4, (void *) iterationThreadAddress, OS_THREAD_SIZE);
|
|
||||||
ret = sendwait(bss, clientfd, buffer, 4 + OS_THREAD_SIZE);
|
|
||||||
CHECK_ERROR(ret < 0)
|
|
||||||
|
|
||||||
// Let the client know that no more threads are coming
|
|
||||||
((int *) buffer)[0] = 0;
|
|
||||||
ret = sendwait(bss, clientfd, buffer, 4);
|
|
||||||
CHECK_ERROR(ret < 0)
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1212,7 +1018,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMMAND_WRITE_SCREEN: {
|
/*case COMMAND_WRITE_SCREEN: {
|
||||||
char message[WRITE_SCREEN_MESSAGE_BUFFER_SIZE];
|
char message[WRITE_SCREEN_MESSAGE_BUFFER_SIZE];
|
||||||
ret = recvwait(bss, clientfd, buffer, 4);
|
ret = recvwait(bss, clientfd, buffer, 4);
|
||||||
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (write screen seconds)")
|
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (write screen seconds)")
|
||||||
@ -1221,7 +1027,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
writeScreen(message, seconds);
|
writeScreen(message, seconds);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}*/
|
||||||
case COMMAND_FOLLOW_POINTER: {
|
case COMMAND_FOLLOW_POINTER: {
|
||||||
ret = recvwait(bss, clientfd, buffer, 8);
|
ret = recvwait(bss, clientfd, buffer, 8);
|
||||||
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (Pointer address and offsets count)")
|
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (Pointer address and offsets count)")
|
||||||
@ -1374,16 +1180,6 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*case COMMAND_SYSTEM_CALL: {
|
|
||||||
ret = recvwait(bss, clientfd, buffer, 4);
|
|
||||||
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (system call)")
|
|
||||||
|
|
||||||
int value = ((int *) buffer)[0];
|
|
||||||
|
|
||||||
performSystemCall(value);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}*/
|
|
||||||
case COMMAND_EXECUTE_ASSEMBLY: {
|
case COMMAND_EXECUTE_ASSEMBLY: {
|
||||||
// Receive the assembly
|
// Receive the assembly
|
||||||
receiveString(bss, clientfd, (char *) buffer, DATA_BUFFER_SIZE);
|
receiveString(bss, clientfd, (char *) buffer, DATA_BUFFER_SIZE);
|
||||||
@ -1441,47 +1237,30 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMMAND_SET_DATA_BREAKPOINT: {
|
case COMMAND_SET_DATA_BREAKPOINT: {
|
||||||
ret = recvwait(bss, clientfd, buffer, 4 + 3 * 1);
|
// Read the data from the client
|
||||||
|
ret = recvwait(bss, clientfd, buffer, sizeof(int) + sizeof(bool) * 2);
|
||||||
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (data breakpoint)");
|
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (data breakpoint)");
|
||||||
|
|
||||||
|
// Parse the data and set the breakpoint
|
||||||
int bufferIndex = 0;
|
int bufferIndex = 0;
|
||||||
unsigned int address = ((unsigned int *) buffer)[bufferIndex];
|
unsigned int address = ((unsigned int *) buffer)[bufferIndex];
|
||||||
bufferIndex += 4;
|
bufferIndex += sizeof(int);
|
||||||
bool translate = buffer[bufferIndex++];
|
|
||||||
bool write = buffer[bufferIndex++];
|
|
||||||
bool read = buffer[bufferIndex];
|
bool read = buffer[bufferIndex];
|
||||||
struct DataBreakpoint dataBreakpoint;
|
bufferIndex += sizeof(bool);
|
||||||
dataBreakpoint.value = address;
|
bool write = buffer[bufferIndex];
|
||||||
dataBreakpoint.translate = translate;
|
bufferIndex += sizeof(bool);
|
||||||
dataBreakpoint.write = write;
|
setDataAddressBreakPointRegister(address, read, write);
|
||||||
dataBreakpoint.read = read;
|
|
||||||
setDataAddressBreakpointRegister(dataBreakpoint);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case COMMAND_GET_DATA_BREAKPOINT: {
|
|
||||||
struct DataBreakpoint dataBreakpoint;
|
|
||||||
getDataAddressBreakpointRegisterContents(dataBreakpoint);
|
|
||||||
int structureSize = sizeof(dataBreakpoint);
|
|
||||||
memcpy(buffer, (const void *) &dataBreakpoint, structureSize);
|
|
||||||
ret = sendwait(bss, clientfd, buffer, structureSize);
|
|
||||||
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (data breakpoint)");
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMMAND_SET_INSTRUCTION_BREAKPOINT: {
|
case COMMAND_SET_INSTRUCTION_BREAKPOINT: {
|
||||||
// Read the address and set the breakpoint execute
|
// Read the address
|
||||||
ret = recvwait(bss, clientfd, buffer, sizeof(int));
|
ret = recvwait(bss, clientfd, buffer, sizeof(int));
|
||||||
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (instruction breakpoint)");
|
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (instruction breakpoint)");
|
||||||
unsigned int address = ((unsigned int *) buffer)[0];
|
|
||||||
setInstructionAddressBreakpointRegister(address);
|
|
||||||
|
|
||||||
break;
|
// Parse the address and set the breakpoint
|
||||||
}
|
unsigned int address = ((unsigned int *) buffer)[0];
|
||||||
case COMMAND_GET_INSTRUCTION_BREAKPOINT: {
|
setInstructionAddressBreakPointRegister(address);
|
||||||
int address = getInstructionAddressBreakpointRegister();
|
|
||||||
((int *) buffer)[0] = address;
|
|
||||||
ret = sendwait(bss, clientfd, buffer, sizeof(int));
|
|
||||||
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (instruction breakpoint)");
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1513,7 +1292,7 @@ struct pygecko_bss_t *bss;
|
|||||||
static int runTCPGeckoServer(int argc, void *argv) {
|
static int runTCPGeckoServer(int argc, void *argv) {
|
||||||
bss = argv;
|
bss = argv;
|
||||||
|
|
||||||
setup_os_exceptions();
|
// setup_os_exceptions();
|
||||||
socket_lib_init();
|
socket_lib_init();
|
||||||
|
|
||||||
log_init(COMPUTER_IP_ADDRESS);
|
log_init(COMPUTER_IP_ADDRESS);
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
#ifndef _PYGECKO_H_
|
#ifndef _PYGECKO_H_
|
||||||
#define _PYGECKO_H_
|
#define _PYGECKO_H_
|
||||||
|
|
||||||
#include "common/types.h"
|
|
||||||
#include "dynamic_libs/os_functions.h"
|
|
||||||
|
|
||||||
/* Main */
|
/* Main */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//! C wrapper for our C++ functions
|
|
||||||
void startTCPGecko(void);
|
void startTCPGecko(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -3,54 +3,6 @@
|
|||||||
#include "../utils/logger.h"
|
#include "../utils/logger.h"
|
||||||
#include "exception_handler.h"
|
#include "exception_handler.h"
|
||||||
|
|
||||||
#define OS_EXCEPTION_MODE_GLOBAL_ALL_CORES 4
|
|
||||||
|
|
||||||
#define OS_EXCEPTION_DSI 2
|
|
||||||
#define OS_EXCEPTION_ISI 3
|
|
||||||
#define OS_EXCEPTION_PROGRAM 6
|
|
||||||
|
|
||||||
/* Exceptions */
|
|
||||||
typedef struct OSContext
|
|
||||||
{
|
|
||||||
/* OSContext identifier */
|
|
||||||
uint32_t tag1;
|
|
||||||
uint32_t tag2;
|
|
||||||
|
|
||||||
/* GPRs */
|
|
||||||
uint32_t gpr[32];
|
|
||||||
|
|
||||||
/* Special registers */
|
|
||||||
uint32_t cr;
|
|
||||||
uint32_t lr;
|
|
||||||
uint32_t ctr;
|
|
||||||
uint32_t xer;
|
|
||||||
|
|
||||||
/* Initial PC and MSR */
|
|
||||||
uint32_t srr0;
|
|
||||||
uint32_t srr1;
|
|
||||||
|
|
||||||
/* Only valid during DSI exception */
|
|
||||||
uint32_t exception_specific0;
|
|
||||||
uint32_t exception_specific1;
|
|
||||||
|
|
||||||
/* There is actually a lot more here but we don't need the rest*/
|
|
||||||
} OSContext;
|
|
||||||
|
|
||||||
#define CPU_STACK_TRACE_DEPTH 10
|
|
||||||
#define __stringify(rn) #rn
|
|
||||||
|
|
||||||
#define mfspr(_rn) \
|
|
||||||
({ register uint32_t _rval = 0; \
|
|
||||||
asm volatile("mfspr %0," __stringify(_rn) \
|
|
||||||
: "=r" (_rval));\
|
|
||||||
_rval; \
|
|
||||||
})
|
|
||||||
|
|
||||||
typedef struct _framerec {
|
|
||||||
struct _framerec *up;
|
|
||||||
void *lr;
|
|
||||||
} frame_rec, *frame_rec_t;
|
|
||||||
|
|
||||||
static const char *exception_names[] = {
|
static const char *exception_names[] = {
|
||||||
"DSI",
|
"DSI",
|
||||||
"ISI",
|
"ISI",
|
||||||
@ -78,33 +30,50 @@ static const char exception_print_formats[18][45] = {
|
|||||||
"%p: %08X %08X %08X %08X\n", // 17
|
"%p: %08X %08X %08X %08X\n", // 17
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned char exception_cb(void * c, unsigned char exception_type) {
|
static unsigned char exceptionCallback(void *c, unsigned char exception_type) {
|
||||||
char buf[850];
|
char stackTraceBuffer[850];
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
OSContext *context = (OSContext *) c;
|
OSContext *context = (OSContext *) c;
|
||||||
/*
|
/*
|
||||||
* This part is mostly from libogc. Thanks to the devs over there.
|
* This part is mostly from libogc. Thanks to the devs over there.
|
||||||
*/
|
*/
|
||||||
pos += sprintf(buf + pos, exception_print_formats[0], exception_names[exception_type]);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[0], exception_names[exception_type]);
|
||||||
pos += sprintf(buf + pos, exception_print_formats[1], context->gpr[0], context->gpr[8], context->gpr[16], context->gpr[24]);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[1], context->gpr[0], context->gpr[8],
|
||||||
pos += sprintf(buf + pos, exception_print_formats[2], context->gpr[1], context->gpr[9], context->gpr[17], context->gpr[25]);
|
context->gpr[16],
|
||||||
pos += sprintf(buf + pos, exception_print_formats[3], context->gpr[2], context->gpr[10], context->gpr[18], context->gpr[26]);
|
context->gpr[24]);
|
||||||
pos += sprintf(buf + pos, exception_print_formats[4], context->gpr[3], context->gpr[11], context->gpr[19], context->gpr[27]);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[2], context->gpr[1], context->gpr[9],
|
||||||
pos += sprintf(buf + pos, exception_print_formats[5], context->gpr[4], context->gpr[12], context->gpr[20], context->gpr[28]);
|
context->gpr[17],
|
||||||
pos += sprintf(buf + pos, exception_print_formats[6], context->gpr[5], context->gpr[13], context->gpr[21], context->gpr[29]);
|
context->gpr[25]);
|
||||||
pos += sprintf(buf + pos, exception_print_formats[7], context->gpr[6], context->gpr[14], context->gpr[22], context->gpr[30]);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[3], context->gpr[2], context->gpr[10],
|
||||||
pos += sprintf(buf + pos, exception_print_formats[8], context->gpr[7], context->gpr[15], context->gpr[23], context->gpr[31]);
|
context->gpr[18],
|
||||||
pos += sprintf(buf + pos, exception_print_formats[9], context->lr, context->srr0, context->srr1);
|
context->gpr[26]);
|
||||||
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[4], context->gpr[3], context->gpr[11],
|
||||||
|
context->gpr[19],
|
||||||
|
context->gpr[27]);
|
||||||
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[5], context->gpr[4], context->gpr[12],
|
||||||
|
context->gpr[20],
|
||||||
|
context->gpr[28]);
|
||||||
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[6], context->gpr[5], context->gpr[13],
|
||||||
|
context->gpr[21],
|
||||||
|
context->gpr[29]);
|
||||||
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[7], context->gpr[6], context->gpr[14],
|
||||||
|
context->gpr[22],
|
||||||
|
context->gpr[30]);
|
||||||
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[8], context->gpr[7], context->gpr[15],
|
||||||
|
context->gpr[23],
|
||||||
|
context->gpr[31]);
|
||||||
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[9], context->lr, context->srr0, context->srr1);
|
||||||
|
|
||||||
//if(exception_type == OS_EXCEPTION_DSI) {
|
//if(exception_type == OS_EXCEPTION_DSI) {
|
||||||
pos += sprintf(buf + pos, exception_print_formats[10], context->exception_specific1, context->exception_specific0); // this freezes
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[10], context->exception_specific1,
|
||||||
|
context->exception_specific0); // this freezes
|
||||||
//}
|
//}
|
||||||
|
|
||||||
void *pc = (void *) context->srr0;
|
void *pc = (void *) context->srr0;
|
||||||
void *lr = (void *) context->lr;
|
void *lr = (void *) context->lr;
|
||||||
void *r1 = (void *) context->gpr[1];
|
void *r1 = (void *) context->gpr[1];
|
||||||
register uint32_t i = 0;
|
register uint32_t currentStackTraceDepth = 0;
|
||||||
register frame_rec_t l, p = (frame_rec_t) lr;
|
register frame_rec_t l, p = (frame_rec_t) lr;
|
||||||
|
|
||||||
l = p;
|
l = p;
|
||||||
@ -112,57 +81,63 @@ static unsigned char exception_cb(void * c, unsigned char exception_type) {
|
|||||||
if (!p)
|
if (!p)
|
||||||
asm volatile("mr %0,%%r1" : "=r"(p));
|
asm volatile("mr %0,%%r1" : "=r"(p));
|
||||||
|
|
||||||
pos += sprintf(buf + pos, exception_print_formats[11]);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[11]);
|
||||||
|
|
||||||
for(i = 0; i < CPU_STACK_TRACE_DEPTH-1 && p->up; p = p->up, i++) {
|
for (currentStackTraceDepth = 0;
|
||||||
if(i % 4)
|
currentStackTraceDepth < CPU_STACK_TRACE_DEPTH - 1 && p->up; p = p->up, currentStackTraceDepth++) {
|
||||||
pos += sprintf(buf + pos, exception_print_formats[12]);
|
if (currentStackTraceDepth % 4)
|
||||||
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[12]);
|
||||||
else {
|
else {
|
||||||
if(i > 0)
|
if (currentStackTraceDepth > 0)
|
||||||
pos += sprintf(buf + pos, exception_print_formats[13]);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[13]);
|
||||||
else
|
else
|
||||||
pos += sprintf(buf + pos, exception_print_formats[14]);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[14]);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(i) {
|
switch (currentStackTraceDepth) {
|
||||||
case 0:
|
case 0:
|
||||||
if (pc)
|
if (pc)
|
||||||
pos += sprintf(buf + pos, exception_print_formats[15],pc);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[15], pc);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (!l)
|
if (!l)
|
||||||
l = (frame_rec_t) mfspr(8);
|
l = (frame_rec_t) mfspr(8);
|
||||||
pos += sprintf(buf + pos, exception_print_formats[15],(void*)l);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[15], (void *) l);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pos += sprintf(buf + pos, exception_print_formats[15],(void*)(p->up->lr));
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[15], (void *) (p->up->lr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if(exception_type == OS_EXCEPTION_DSI) {
|
//if(exception_type == OS_EXCEPTION_DSI) {
|
||||||
uint32_t *pAdd = (uint32_t *) context->srr0;
|
uint32_t *pAdd = (uint32_t *) context->srr0;
|
||||||
pos += sprintf(buf + pos, exception_print_formats[16]);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[16]);
|
||||||
// TODO by Dimok: this was actually be 3 instead of 2 lines in libogc .... but there is just no more space anymore on the screen
|
// TODO by Dimok: this was actually be 3 instead of 2 lines in libogc .... but there is just no more space anymore on the screen
|
||||||
for (i = 0; i < 8; i += 4)
|
for (currentStackTraceDepth = 0; currentStackTraceDepth < 8; currentStackTraceDepth += 4)
|
||||||
pos += sprintf(buf + pos, exception_print_formats[17], &(pAdd[i]),pAdd[i], pAdd[i+1], pAdd[i+2], pAdd[i+3]);
|
pos += sprintf(stackTraceBuffer + pos, exception_print_formats[17], &(pAdd[currentStackTraceDepth]),
|
||||||
|
pAdd[currentStackTraceDepth], pAdd[currentStackTraceDepth + 1], pAdd[currentStackTraceDepth + 2],
|
||||||
|
pAdd[currentStackTraceDepth + 3]);
|
||||||
//}
|
//}
|
||||||
log_print(buf);
|
log_print(stackTraceBuffer);
|
||||||
OSFatal(buf);
|
OSFatal(stackTraceBuffer);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char dsi_exception_cb(void *context) {
|
static unsigned char dsi_exception_cb(void *context) {
|
||||||
return exception_cb(context, 0);
|
return exceptionCallback(context, 0);
|
||||||
}
|
|
||||||
static unsigned char isi_exception_cb(void * context) {
|
|
||||||
return exception_cb(context, 1);
|
|
||||||
}
|
|
||||||
static unsigned char program_exception_cb(void * context) {
|
|
||||||
return exception_cb(context, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_os_exceptions(void) {
|
static unsigned char isi_exception_cb(void *context) {
|
||||||
|
return exceptionCallback(context, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char program_exception_cb(void *context) {
|
||||||
|
return exceptionCallback(context, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_os_exceptions() {
|
||||||
OSSetExceptionCallback(OS_EXCEPTION_DSI, &dsi_exception_cb);
|
OSSetExceptionCallback(OS_EXCEPTION_DSI, &dsi_exception_cb);
|
||||||
OSSetExceptionCallback(OS_EXCEPTION_ISI, &isi_exception_cb);
|
OSSetExceptionCallback(OS_EXCEPTION_ISI, &isi_exception_cb);
|
||||||
OSSetExceptionCallback(OS_EXCEPTION_PROGRAM, &program_exception_cb);
|
OSSetExceptionCallback(OS_EXCEPTION_PROGRAM, &program_exception_cb);
|
||||||
|
@ -5,6 +5,52 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "../utils/stringify.h"
|
||||||
|
|
||||||
|
#define OS_EXCEPTION_DSI 2
|
||||||
|
#define OS_EXCEPTION_ISI 3
|
||||||
|
#define OS_EXCEPTION_PROGRAM 6
|
||||||
|
|
||||||
|
/* Exceptions */
|
||||||
|
typedef struct OSContext {
|
||||||
|
/* OSContext identifier */
|
||||||
|
uint32_t tag1;
|
||||||
|
uint32_t tag2;
|
||||||
|
|
||||||
|
/* GPRs */
|
||||||
|
uint32_t gpr[32];
|
||||||
|
|
||||||
|
/* Special registers */
|
||||||
|
uint32_t cr;
|
||||||
|
uint32_t lr;
|
||||||
|
uint32_t ctr;
|
||||||
|
uint32_t xer;
|
||||||
|
|
||||||
|
/* Initial PC and MSR */
|
||||||
|
uint32_t srr0;
|
||||||
|
uint32_t srr1;
|
||||||
|
|
||||||
|
/* Only valid during DSI exception */
|
||||||
|
uint32_t exception_specific0;
|
||||||
|
uint32_t exception_specific1;
|
||||||
|
|
||||||
|
/* There is actually a lot more here but we don't need the rest*/
|
||||||
|
} OSContext;
|
||||||
|
|
||||||
|
#define CPU_STACK_TRACE_DEPTH 10
|
||||||
|
|
||||||
|
#define mfspr(_rn) \
|
||||||
|
({ register uint32_t _rval = 0; \
|
||||||
|
asm volatile("mfspr %0," __stringify(_rn) \
|
||||||
|
: "=r" (_rval));\
|
||||||
|
_rval; \
|
||||||
|
})
|
||||||
|
|
||||||
|
typedef struct _framerec {
|
||||||
|
struct _framerec *up;
|
||||||
|
void *lr;
|
||||||
|
} frame_rec, *frame_rec_t;
|
||||||
|
|
||||||
void setup_os_exceptions(void);
|
void setup_os_exceptions(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
void m_DCFlushRange(unsigned int startAddr, unsigned int size)
|
|
||||||
{
|
|
||||||
register unsigned int addr = startAddr & ~0x1F;
|
|
||||||
register unsigned int end_addr = startAddr + size;
|
|
||||||
|
|
||||||
while(addr < end_addr)
|
|
||||||
{
|
|
||||||
asm volatile("dcbf 0, %0" : : "r"(addr));
|
|
||||||
addr += 0x20;
|
|
||||||
}
|
|
||||||
asm volatile("sync; eieio");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void m_DCInvalidateRange(unsigned int startAddr, unsigned int size)
|
|
||||||
{
|
|
||||||
register unsigned int addr = startAddr & ~0x1F;
|
|
||||||
register unsigned int end_addr = startAddr + size;
|
|
||||||
|
|
||||||
while(addr < end_addr)
|
|
||||||
{
|
|
||||||
asm volatile("dcbi 0, %0" : : "r"(addr));
|
|
||||||
addr += 0x20;
|
|
||||||
}
|
|
||||||
}
|
|
BIN
tcpgecko.elf
BIN
tcpgecko.elf
Binary file not shown.
Loading…
Reference in New Issue
Block a user