mirror of
https://github.com/decaf-emu/decaf-emu.git
synced 2025-04-02 10:42:13 -04:00
209 lines
5.3 KiB
C
209 lines
5.3 KiB
C
#include "program.h"
|
|
#include "console.h"
|
|
#include "sysfuncs.h"
|
|
|
|
#define CLIENT_VERSION 1
|
|
|
|
#define ALIGN_BACKWARD(x,align) \
|
|
((typeof(x))(((unsigned int)(x)) & (~(align-1))))
|
|
|
|
int sendwait(struct SystemFunctions *sysFuncs, int sock, const void *buffer, int len);
|
|
int recvwait(struct SystemFunctions *sysFuncs, int sock, void *buffer, int len);
|
|
|
|
struct PacketHeader
|
|
{
|
|
uint16_t size;
|
|
uint16_t command;
|
|
};
|
|
|
|
struct VersionPacket
|
|
{
|
|
struct PacketHeader header;
|
|
uint32_t version;
|
|
};
|
|
|
|
struct ExecuteCodeTestPacket
|
|
{
|
|
struct PacketHeader header;
|
|
uint32_t instr;
|
|
struct TestState state;
|
|
};
|
|
|
|
void writeInstruction(struct SystemFunctions *sysFuncs, void *func, uint32_t instr)
|
|
{
|
|
// Write code
|
|
uint32_t *topatch = (uint32_t*)(0xA0000000 + (uint32_t)func);
|
|
topatch[0] = instr; // instr
|
|
topatch[1] = 0x4E800020; // blr
|
|
|
|
// Flush caches
|
|
unsigned int *faddr = ALIGN_BACKWARD(topatch, 32);
|
|
sysFuncs->DCFlushRange(faddr, 0x40);
|
|
sysFuncs->ICInvalidateRange(faddr, 0x40);
|
|
}
|
|
|
|
void _entryPoint()
|
|
{
|
|
struct SystemFunctions sysFuncs;
|
|
struct ConsoleData consoleData;
|
|
|
|
loadSysFuncs(&sysFuncs);
|
|
allocConsole(&sysFuncs, &consoleData);
|
|
|
|
char *packetBuffer = (char *)sysFuncs.OSAllocFromSystem(4096, 16);
|
|
sysFuncs.socket_lib_init();
|
|
|
|
int error;
|
|
VPADData vpad_data;
|
|
sysFuncs.VPADRead(0, &vpad_data, 1, &error);
|
|
|
|
struct sockaddr sin;
|
|
sysFuncs.memset(&sin, 0, sizeof(struct sockaddr));
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = 8008;
|
|
sin.sin_addr.s_addr = ((192<<24) | (168<<16) | (1<<8) | (67<<0));
|
|
LOG(&consoleData, "Create socket");
|
|
int sockfd = sysFuncs.socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
LOG(&consoleData, "Connecting...");
|
|
int status = sysFuncs.connect(sockfd, &sin, 0x10);
|
|
LOG(&consoleData, "Connected.");
|
|
|
|
bool hasKernelPermissions = false;
|
|
bool running = true;
|
|
|
|
if (sysFuncs.OSEffectiveToPhysical((void *)0xA0000000) != (void *)0x31000000) {
|
|
LOG(&consoleData, "Running without kernel permissions");
|
|
hasKernelPermissions = false;
|
|
} else {
|
|
hasKernelPermissions = true;
|
|
}
|
|
|
|
if (status) {
|
|
sockfd = 0;
|
|
LOG(&consoleData, "Error connecting to server, status = %d", status);
|
|
} else {
|
|
while (running) {
|
|
// Read packet header
|
|
if (recvwait(&sysFuncs, sockfd, packetBuffer, 4) <= 0) {
|
|
LOG(&consoleData, "Error reading packet header");
|
|
break;
|
|
}
|
|
|
|
// Read packet data
|
|
uint16_t packetSize = ((uint16_t*)packetBuffer)[0];
|
|
uint16_t packetCmd = ((uint16_t*)packetBuffer)[1];
|
|
uint16_t remaining = packetSize - 4;
|
|
|
|
if (remaining) {
|
|
if (recvwait(&sysFuncs, sockfd, packetBuffer + 4, remaining) <= 0) {
|
|
LOG(&consoleData, "Error reading packet data");
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Process packet
|
|
switch(packetCmd) {
|
|
case 1: {
|
|
// Version
|
|
struct VersionPacket *packet = (struct VersionPacket*)packetBuffer;
|
|
LOG(&consoleData, "Received server version %d", packet->version);
|
|
|
|
// Reply with client version
|
|
packet->version = CLIENT_VERSION;
|
|
if (sendwait(&sysFuncs, sockfd, packet, packet->header.size) <= 0) {
|
|
LOG(&consoleData, "Error sending version packet");
|
|
running = false;
|
|
}
|
|
} break;
|
|
case 10: {
|
|
struct ExecuteCodeTestPacket *packet = (struct ExecuteCodeTestPacket*)packetBuffer;
|
|
|
|
if (hasKernelPermissions) {
|
|
writeInstruction(&sysFuncs, sysFuncs.PPCMtpmc4, packet->instr);
|
|
executeCodeTest(&packet->state, sysFuncs.PPCMtpmc4);
|
|
} else {
|
|
LOG(&consoleData, "Skipping code test %08X (requires kernel permissions)", packet->instr);
|
|
}
|
|
|
|
// Reply with test results
|
|
if (sendwait(&sysFuncs, sockfd, packet, packet->header.size) <= 0) {
|
|
LOG(&consoleData, "Error sending test results.");
|
|
running = false;
|
|
}
|
|
} break;
|
|
case 11: {
|
|
LOG(&consoleData, "Tests finished");
|
|
running = false;
|
|
} break;
|
|
}
|
|
}
|
|
}
|
|
|
|
renderLoop:
|
|
while(1)
|
|
{
|
|
sysFuncs.VPADRead(0, &vpad_data, 1, &error);
|
|
|
|
// Exit when HOME button pressed
|
|
if(vpad_data.btn_hold & BUTTON_HOME) {
|
|
break;
|
|
}
|
|
|
|
renderConsole(&consoleData);
|
|
}
|
|
|
|
// Safely exit
|
|
{
|
|
unsigned i;
|
|
sysFuncs.socket_lib_finish();
|
|
freeConsole(&sysFuncs, &consoleData);
|
|
sysFuncs.OSFreeToSystem(packetBuffer);
|
|
|
|
for(i = 0; i < 2; i++)
|
|
{
|
|
fillScreen(0,0,0,0);
|
|
flipBuffers();
|
|
}
|
|
|
|
sysFuncs._Exit();
|
|
}
|
|
}
|
|
|
|
int recvwait(struct SystemFunctions *sysFuncs, int sock, void *buffer, int len)
|
|
{
|
|
int ret;
|
|
int recvd = 0;
|
|
|
|
while (len > 0) {
|
|
ret = sysFuncs->recv(sock, buffer, len, 0);
|
|
|
|
if (ret <= 0) {
|
|
return ret;
|
|
}
|
|
|
|
recvd += ret;
|
|
len -= ret;
|
|
buffer += ret;
|
|
}
|
|
|
|
return recvd;
|
|
}
|
|
|
|
int sendwait(struct SystemFunctions *sysFuncs, int sock, const void *buffer, int len)
|
|
{
|
|
int ret;
|
|
int recvd = 0;
|
|
|
|
while (len > 0) {
|
|
ret = sysFuncs->send(sock, buffer, len, 0);
|
|
|
|
if (ret <= 0) {
|
|
return ret;
|
|
}
|
|
|
|
len -= ret;
|
|
buffer += ret;
|
|
}
|
|
|
|
return recvd;
|
|
}
|