From 152c96a34a8176b510460f88642b0094bc8961d3 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 14 Jan 2021 18:18:07 +0900 Subject: [PATCH] Import UART proxy Signed-off-by: Hector Martin --- Makefile | 4 +- src/main.c | 10 +++- src/proxy.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ src/proxy.h | 67 +++++++++++++++++++++++ src/startup.c | 6 +- src/uart.c | 21 +++++-- src/uart.h | 8 ++- src/uartproxy.c | 124 +++++++++++++++++++++++++++++++++++++++++ src/uartproxy.h | 6 ++ src/utils.c | 4 +- src/utils.h | 64 +++++++++++++++++++--- src/utils_asm.S | 23 ++++++++ src/xnuboot.h | 1 + 13 files changed, 460 insertions(+), 21 deletions(-) create mode 100644 src/proxy.c create mode 100644 src/proxy.h create mode 100644 src/uartproxy.c create mode 100644 src/uartproxy.h diff --git a/Makefile b/Makefile index a494a12e..0bd9c7d0 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/src/main.c b/src/main.c index f7312be7..d96c8507 100644 --- a/src/main.c +++ b/src/main.c @@ -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) ; } diff --git a/src/proxy.c b/src/proxy.c new file mode 100644 index 00000000..ea8a82c0 --- /dev/null +++ b/src/proxy.c @@ -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; +} diff --git a/src/proxy.h b/src/proxy.h new file mode 100644 index 00000000..80925d06 --- /dev/null +++ b/src/proxy.h @@ -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 diff --git a/src/startup.c b/src/startup.c index 0cda51f8..e47acada 100644 --- a/src/startup.c +++ b/src/startup.c @@ -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); diff --git a/src/uart.c b/src/uart.c index 399f54bd..6360563d 100644 --- a/src/uart.c +++ b/src/uart.c @@ -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; } diff --git a/src/uart.h b/src/uart.h index fbe157c4..de4c1f07 100644 --- a/src/uart.h +++ b/src/uart.h @@ -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); diff --git a/src/uartproxy.c b/src/uartproxy.c new file mode 100644 index 00000000..834dd079 --- /dev/null +++ b/src/uartproxy.c @@ -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); + } + } +} diff --git a/src/uartproxy.h b/src/uartproxy.h new file mode 100644 index 00000000..ab759ffe --- /dev/null +++ b/src/uartproxy.h @@ -0,0 +1,6 @@ +#ifndef __GECKOPROXY_H__ +#define __GECKOPROXY_H__ + +void uartproxy_run(void); + +#endif diff --git a/src/utils.c b/src/utils.c index b9d0a1f4..cf930b96 100644 --- a/src/utils.c +++ b/src/utils.c @@ -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); diff --git a/src/utils.h b/src/utils.h index 5a21f2c7..cca22896 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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 -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, ...); diff --git a/src/utils_asm.S b/src/utils_asm.S index a41f57fb..c2c56907 100644 --- a/src/utils_asm.S +++ b/src/utils_asm.S @@ -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: diff --git a/src/xnuboot.h b/src/xnuboot.h index c304df04..32623b3e 100644 --- a/src/xnuboot.h +++ b/src/xnuboot.h @@ -30,6 +30,7 @@ struct boot_args { u64 mem_size_actual; }; +extern u64 boot_args_addr; extern struct boot_args cur_boot_args; #endif