mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-21 22:23:05 +00:00
Import UART proxy
Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
8af9f1eb95
commit
152c96a34a
13 changed files with 460 additions and 21 deletions
4
Makefile
4
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
|
||||
|
|
10
src/main.c
10
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)
|
||||
;
|
||||
}
|
||||
|
|
143
src/proxy.c
Normal file
143
src/proxy.c
Normal 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
67
src/proxy.h
Normal 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
|
|
@ -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);
|
||||
|
|
21
src/uart.c
21
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;
|
||||
}
|
||||
|
|
|
@ -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
124
src/uartproxy.c
Normal 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
6
src/uartproxy.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef __GECKOPROXY_H__
|
||||
#define __GECKOPROXY_H__
|
||||
|
||||
void uartproxy_run(void);
|
||||
|
||||
#endif
|
|
@ -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);
|
||||
|
|
64
src/utils.h
64
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 <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, ...);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -30,6 +30,7 @@ struct boot_args {
|
|||
u64 mem_size_actual;
|
||||
};
|
||||
|
||||
extern u64 boot_args_addr;
|
||||
extern struct boot_args cur_boot_args;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue