Import UART proxy

Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
Hector Martin 2021-01-14 18:18:07 +09:00
parent 8af9f1eb95
commit 152c96a34a
13 changed files with 460 additions and 21 deletions

View file

@ -7,8 +7,8 @@ LDFLAGS := -T m1n1.ld -EL -maarch64elf --no-undefined -X -shared -Bsymbolic \
-z notext --no-apply-dynamic-relocs --orphan-handling=warn --strip-debug \
-z nocopyreloc \
OBJECTS := bootlogo_128.o bootlogo_256.o fb.o main.o start.o startup.o \
string.o uart.o utils.o utils_asm.o vsprintf.o
OBJECTS := bootlogo_128.o bootlogo_256.o fb.o main.o proxy.o start.o startup.o \
string.o uart.o uartproxy.o utils.o utils_asm.o vsprintf.o
BUILD_OBJS := $(patsubst %,build/%,$(OBJECTS))
NAME := m1n1

View file

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: MIT */
#include "fb.h"
#include "uart.h"
#include "uartproxy.h"
#include "utils.h"
#include "xnuboot.h"
@ -18,8 +20,14 @@ void m1n1_main(void)
u64 dtaddr = ((u64)cur_boot_args.devtree) - cur_boot_args.virt_base +
cur_boot_args.phys_base;
hexdump((void *)dtaddr, cur_boot_args.devtree_size);
// hexdump((void *)dtaddr, cur_boot_args.devtree_size);
//
// while (1)
// uart_putbyte(uart_getbyte());
printf("Running proxy...\n");
uartproxy_run();
while (1)
;
}

143
src/proxy.c Normal file
View file

@ -0,0 +1,143 @@
#include "proxy.h"
#include "types.h"
#include "utils.h"
#include "xnuboot.h"
int proxy_process(ProxyRequest *request, ProxyReply *reply)
{
callfunc *f;
reply->opcode = request->opcode;
reply->status = S_OK;
reply->retval = 0;
switch (request->opcode) {
case P_NOP:
break;
case P_EXIT:
return 0;
case P_CALL:
f = (callfunc *)request->args[0];
reply->retval = f(request->args[1], request->args[2],
request->args[3], request->args[4]);
break;
case P_GET_BOOTARGS:
reply->retval = boot_args_addr;
break;
case P_WRITE64:
write64(request->args[0], request->args[1]);
break;
case P_WRITE32:
write32(request->args[0], request->args[1]);
break;
case P_WRITE16:
write16(request->args[0], request->args[1]);
break;
case P_WRITE8:
write8(request->args[0], request->args[1]);
break;
case P_READ64:
reply->retval = read64(request->args[0]);
break;
case P_READ32:
reply->retval = read32(request->args[0]);
break;
case P_READ16:
reply->retval = read16(request->args[0]);
break;
case P_READ8:
reply->retval = read8(request->args[0]);
break;
case P_SET64:
reply->retval = set64(request->args[0], request->args[1]);
break;
case P_SET32:
reply->retval = set32(request->args[0], request->args[1]);
break;
case P_SET16:
reply->retval = set16(request->args[0], request->args[1]);
break;
case P_SET8:
reply->retval = set8(request->args[0], request->args[1]);
break;
case P_CLEAR64:
reply->retval = clear64(request->args[0], request->args[1]);
break;
case P_CLEAR32:
reply->retval = clear32(request->args[0], request->args[1]);
break;
case P_CLEAR16:
reply->retval = clear16(request->args[0], request->args[1]);
break;
case P_CLEAR8:
reply->retval = clear8(request->args[0], request->args[1]);
break;
case P_MASK64:
reply->retval =
mask64(request->args[0], request->args[1], request->args[2]);
break;
case P_MASK32:
reply->retval =
mask32(request->args[0], request->args[1], request->args[2]);
break;
case P_MASK16:
reply->retval =
mask16(request->args[0], request->args[1], request->args[2]);
break;
case P_MASK8:
reply->retval =
mask8(request->args[0], request->args[1], request->args[2]);
break;
case P_MEMCPY64:
memcpy64((void *)request->args[0], (void *)request->args[1],
request->args[2]);
break;
case P_MEMCPY32:
memcpy32((void *)request->args[0], (void *)request->args[1],
request->args[2]);
break;
case P_MEMCPY16:
memcpy16((void *)request->args[0], (void *)request->args[1],
request->args[2]);
break;
case P_MEMCPY8:
memcpy8((void *)request->args[0], (void *)request->args[1],
request->args[2]);
break;
case P_MEMSET64:
memset64((void *)request->args[0], request->args[1],
request->args[2]);
break;
case P_MEMSET32:
memset32((void *)request->args[0], request->args[1],
request->args[2]);
break;
case P_MEMSET16:
memset16((void *)request->args[0], request->args[1],
request->args[2]);
break;
case P_MEMSET8:
memset8((void *)request->args[0], request->args[1],
request->args[2]);
break;
/*
case P_DC_FLUSHRANGE: dc_flushrange((void*)request->args[0],
request->args[1]); break; case P_DC_INVALRANGE:
dc_invalidaterange((void*)request->args[0], request->args[1]);
break; case P_DC_FLUSHALL: dc_flushall(); break; case
P_IC_INVALALL: ic_invalidateall(); break;
*/
default:
reply->status = S_BADCMD;
break;
}
return 1;
}

67
src/proxy.h Normal file
View file

@ -0,0 +1,67 @@
#ifndef __PROXY_H__
#define __PROXY_H__
#include "types.h"
typedef enum {
P_NOP = 0x000, // System functions
P_EXIT,
P_CALL,
P_GET_BOOTARGS,
P_WRITE64 = 0x100, // Generic register functions
P_WRITE32,
P_WRITE16,
P_WRITE8,
P_READ64,
P_READ32,
P_READ16,
P_READ8,
P_SET64,
P_SET32,
P_SET16,
P_SET8,
P_CLEAR64,
P_CLEAR32,
P_CLEAR16,
P_CLEAR8,
P_MASK64,
P_MASK32,
P_MASK16,
P_MASK8,
P_MEMCPY64 = 0x200, // Memory block transfer functions
P_MEMCPY32,
P_MEMCPY16,
P_MEMCPY8,
P_MEMSET64,
P_MEMSET32,
P_MEMSET16,
P_MEMSET8,
P_DC_FLUSHRANGE = 0x300, // Cache and memory ops
P_DC_INVALRANGE,
P_DC_FLUSHALL,
P_IC_INVALALL,
} ProxyOp;
#define S_OK 0
#define S_BADCMD -1
typedef u64(callfunc)(u64, u64, u64, u64);
typedef struct {
u64 opcode;
u64 args[6];
} ProxyRequest;
typedef struct {
u64 opcode;
s64 status;
u64 retval;
} ProxyReply;
int proxy_process(ProxyRequest *request, ProxyReply *reply);
#endif

View file

@ -6,6 +6,7 @@
#include "utils.h"
#include "xnuboot.h"
u64 boot_args_addr;
struct boot_args cur_boot_args;
struct rela_entry {
@ -62,13 +63,14 @@ void dump_boot_args(struct boot_args *ba)
void _start_c(void *boot_args, void *base)
{
uart_putc('s');
uart_putchar('s');
uart_init();
uart_putc('c');
uart_putchar('c');
uart_puts(": Initializing\n");
printf("boot_args at %p\n", boot_args);
boot_args_addr = (u64)boot_args;
memcpy(&cur_boot_args, boot_args, sizeof(cur_boot_args));
dump_boot_args(&cur_boot_args);

View file

@ -33,7 +33,15 @@ void uart_putbyte(u8 c)
write32(UART_BASE + UTXH, c);
}
void uart_putc(u8 c)
u8 uart_getbyte(void)
{
while (!(read32(UART_BASE + UTRSTAT) & 0x01))
;
return read32(UART_BASE + URXH);
}
void uart_putchar(u8 c)
{
if (c == '\n')
uart_putbyte('\r');
@ -41,12 +49,17 @@ void uart_putc(u8 c)
uart_putbyte(c);
}
u8 uart_getchar(void)
{
return 0;
}
void uart_puts(const char *s)
{
while (*s)
uart_putc(*(s++));
uart_putchar(*(s++));
uart_putc('\n');
uart_putchar('\n');
}
void uart_write(const void *buf, size_t count)
@ -57,7 +70,7 @@ void uart_write(const void *buf, size_t count)
uart_putbyte(*p++);
}
u8 uart_getc(void)
size_t uart_read(const void *buf, size_t count)
{
return 0;
}

View file

@ -5,10 +5,14 @@
void uart_init(void);
void uart_putc(u8 c);
u8 uart_getc(void);
void uart_putbyte(u8 c);
u8 uart_getbyte(void);
void uart_putchar(u8 c);
u8 uart_getchar(void);
void uart_write(const void *buf, size_t count);
size_t uart_read(const void *buf, size_t count);
void uart_puts(const char *s);

124
src/uartproxy.c Normal file
View file

@ -0,0 +1,124 @@
#include "proxy.h"
#include "string.h"
#include "types.h"
#include "uart.h"
typedef struct {
u32 _pad;
u32 type;
union {
ProxyRequest prequest;
struct {
u64 addr;
u64 size;
u32 dchecksum;
} mrequest;
};
u32 checksum;
} UartRequest;
typedef struct {
u32 type;
u32 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 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;
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, sizeof(request) - 4);
if (bytes != (sizeof(UartRequest) - 4))
continue;
if (checksum(&(request.type), sizeof(request) - 8) != 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, sizeof(reply) - 4);
uart_write(&reply, sizeof(reply));
if ((request.type == REQ_MEMREAD) && (reply.status == ST_OK)) {
uart_write((void *)request.mrequest.addr,
request.mrequest.size);
}
}
}

6
src/uartproxy.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef __GECKOPROXY_H__
#define __GECKOPROXY_H__
void uartproxy_run(void);
#endif

View file

@ -16,10 +16,10 @@ static char ascii(char s)
return s;
}
void hexdump(const void *d, int len)
void hexdump(const void *d, size_t len)
{
u8 *data;
int i, off;
size_t i, off;
data = (u8 *)d;
for (off = 0; off < len; off += 16) {
printf("%08x ", off);

View file

@ -7,6 +7,52 @@
#define printf debug_printf
static inline u64 read64(u64 addr)
{
u64 data;
__asm__ volatile("ldr\t%0, [%1]" : "=r"(data) : "r"(addr));
return data;
}
static inline void write64(u64 addr, u64 data)
{
__asm__ volatile("str\t%0, [%1]" : : "r"(data), "r"(addr));
}
static inline u64 set64(u64 addr, u64 set)
{
u64 data;
__asm__ volatile("ldr\t%0, [%1]\n"
"\torr\t%0, %0, %2\n"
"\tstr\t%0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(set));
return data;
}
static inline u64 clear64(u64 addr, u64 clear)
{
u64 data;
__asm__ volatile("ldr\t%0, [%1]\n"
"\tbic\t%0, %0, %2\n"
"\tstr\t%0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(clear));
return data;
}
static inline u64 mask64(u64 addr, u64 clear, u64 set)
{
u64 data;
__asm__ volatile("ldr\t%0, [%1]\n"
"\tbic\t%0, %0, %3\n"
"\torr\t%0, %0, %2\n"
"\tstr\t%0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(set), "r"(clear));
return data;
}
static inline u32 read32(u64 addr)
{
u32 data;
@ -93,7 +139,7 @@ static inline u16 mask16(u64 addr, u16 clear, u16 set)
{
u16 data;
__asm__ volatile("ldrh\t%w0, [%1]\n"
"\tbic\t%w0, %3\n"
"\tbic\t%w0, %w0, %w3\n"
"\torr\t%w0, %w0, %w2\n"
"\tstrh\t%w0, [%1]"
: "=&r"(data)
@ -151,14 +197,16 @@ static inline u8 mask8(u64 addr, u8 clear, u8 set)
* These functions are guaranteed to copy by reading from src and writing to dst
* in <n>-bit units If size is not aligned, the remaining bytes are not copied
*/
void memset32(void *dst, u32 value, u32 size);
void memcpy32(void *dst, void *src, u32 size);
void memset16(void *dst, u16 value, u32 size);
void memcpy16(void *dst, void *src, u32 size);
void memset8(void *dst, u8 value, u32 size);
void memcpy8(void *dst, void *src, u32 size);
void memset64(void *dst, u64 value, size_t size);
void memcpy64(void *dst, void *src, size_t size);
void memset32(void *dst, u32 value, size_t size);
void memcpy32(void *dst, void *src, size_t size);
void memset16(void *dst, u16 value, size_t size);
void memcpy16(void *dst, void *src, size_t size);
void memset8(void *dst, u8 value, size_t size);
void memcpy8(void *dst, void *src, size_t size);
void hexdump(const void *d, int len);
void hexdump(const void *d, size_t len);
void regdump(u64 addr, int len);
int sprintf(char *str, const char *fmt, ...);
int debug_printf(const char *fmt, ...);

View file

@ -2,6 +2,29 @@
.text
.globl memcpy64
.type memcpy64, @function
memcpy64:
ands x2, x2, #~7
beq 2f
1: ldr x3, [x1], #8
str x3, [x0], #8
subs x2, x2, #8
bne 1b
2:
ret
.globl memset64
.type memset64, @function
memset64:
ands x2, x2, #~7
beq 2f
1: str x1, [x0], #8
subs x2, x2, #8
bne 1b
2:
ret
.globl memcpy32
.type memcpy32, @function
memcpy32:

View file

@ -30,6 +30,7 @@ struct boot_args {
u64 mem_size_actual;
};
extern u64 boot_args_addr;
extern struct boot_args cur_boot_args;
#endif