m1n1/src/uartproxy.c
Hector Martin 5175c7a31b Chainloading, ADT support, misc fixes
Signed-off-by: Hector Martin <marcan@marcan.st>
2021-01-15 04:04:12 +09:00

131 lines
3.3 KiB
C

#include "proxy.h"
#include "string.h"
#include "types.h"
#include "uart.h"
#include "utils.h"
#define REQ_SIZE 64
typedef struct {
u32 _pad;
u32 type;
union {
ProxyRequest prequest;
struct {
u64 addr;
u64 size;
u32 dchecksum;
} mrequest;
};
u32 checksum;
} UartRequest;
#define REPLY_SIZE 36
typedef struct {
u32 type;
s32 status;
union {
ProxyReply preply;
struct {
u32 dchecksum;
} mreply;
};
u32 checksum;
} UartReply;
#define REQ_NOP 0x00AA55FF
#define REQ_PROXY 0x01AA55FF
#define REQ_MEMREAD 0x02AA55FF
#define REQ_MEMWRITE 0x03AA55FF
#define REQ_BOOT 0x04AA55FF
#define ST_OK 0
#define ST_BADCMD -1
#define ST_INVAL -2
#define ST_XFRERR -3
#define ST_CRCERR -4
// I just totally pulled this out of my arse
u32 checksum(void *start, u32 length)
{
u32 sum = 0xDEADBEEF;
u8 *d = (u8 *)start;
while (length--) {
sum *= 31337;
sum += (*d++) ^ 0x5A;
}
return sum ^ 0xADDEDBAD;
}
void uartproxy_run(void)
{
int running = 1;
int c;
u32 bytes;
UartRequest request;
UartReply reply = {REQ_BOOT};
reply.checksum = checksum(&reply, REPLY_SIZE - 4);
uart_write(&reply, REPLY_SIZE);
while (running) {
c = uart_getbyte();
if (c != 0xFF)
continue;
c = uart_getbyte();
if (c != 0x55)
continue;
c = uart_getbyte();
if (c != 0xAA)
continue;
c = uart_getbyte();
if (c < 0)
continue;
memset(&request, 0, sizeof(request));
request.type = 0x00AA55FF | ((c & 0xff) << 24);
bytes = uart_read((&request.type) + 1, REQ_SIZE - 4);
if (bytes != REQ_SIZE - 4)
continue;
if (checksum(&(request.type), REQ_SIZE - 4) != request.checksum)
continue;
memset(&reply, 0, sizeof(reply));
reply.type = request.type;
reply.status = ST_OK;
switch (request.type) {
case REQ_NOP:
break;
case REQ_PROXY:
running = proxy_process(&request.prequest, &reply.preply);
break;
case REQ_MEMREAD:
reply.mreply.dchecksum = checksum((void *)request.mrequest.addr,
request.mrequest.size);
break;
case REQ_MEMWRITE:
bytes = uart_read((void *)request.mrequest.addr,
request.mrequest.size);
if (bytes != request.mrequest.size) {
reply.status = ST_XFRERR;
break;
}
reply.mreply.dchecksum = checksum((void *)request.mrequest.addr,
request.mrequest.size);
if (reply.mreply.dchecksum != request.mrequest.dchecksum)
reply.status = ST_XFRERR;
break;
default:
reply.status = ST_BADCMD;
break;
}
reply.checksum = checksum(&reply, REPLY_SIZE - 4);
uart_write(&reply, REPLY_SIZE);
if ((request.type == REQ_MEMREAD) && (reply.status == ST_OK)) {
uart_write((void *)request.mrequest.addr, request.mrequest.size);
}
}
}