decaf-emu/tests/cpu/generator/client/program.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;
}