artiq/soc/runtime/ksupport.c

380 lines
9.5 KiB
C

#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <link.h>
#include <dlfcn.h>
#include <dyld.h>
#include <unwind.h>
#include "ksupport.h"
#include "kloader.h"
#include "mailbox.h"
#include "messages.h"
#include "bridge.h"
#include "artiq_personality.h"
#include "ttl.h"
#include "dds.h"
#include "rtio.h"
void ksupport_abort(void);
int64_t now;
/* compiler-rt symbols */
extern void __divsi3, __modsi3, __ledf2, __gedf2, __unorddf2, __eqdf2, __ltdf2,
__nedf2, __gtdf2, __negsf2, __negdf2, __addsf3, __subsf3, __mulsf3,
__divsf3, __lshrdi3, __muldi3, __divdi3, __ashldi3, __ashrdi3,
__udivmoddi4, __floatsisf, __floatunsisf, __fixsfsi, __fixunssfsi,
__adddf3, __subdf3, __muldf3, __divdf3, __floatsidf, __floatunsidf,
__floatdidf, __fixdfsi, __fixdfdi, __fixunsdfsi, __clzsi2, __ctzsi2,
__udivdi3, __umoddi3, __moddi3;
/* artiq_personality symbols */
extern void __artiq_personality;
struct symbol {
const char *name;
void *addr;
};
static const struct symbol runtime_exports[] = {
/* compiler-rt */
{"divsi3", &__divsi3},
{"modsi3", &__modsi3},
{"ledf2", &__ledf2},
{"gedf2", &__gedf2},
{"unorddf2", &__unorddf2},
{"eqdf2", &__eqdf2},
{"ltdf2", &__ltdf2},
{"nedf2", &__nedf2},
{"gtdf2", &__gtdf2},
{"negsf2", &__negsf2},
{"negdf2", &__negdf2},
{"addsf3", &__addsf3},
{"subsf3", &__subsf3},
{"mulsf3", &__mulsf3},
{"divsf3", &__divsf3},
{"lshrdi3", &__lshrdi3},
{"muldi3", &__muldi3},
{"divdi3", &__divdi3},
{"ashldi3", &__ashldi3},
{"ashrdi3", &__ashrdi3},
{"udivmoddi4", &__udivmoddi4},
{"floatsisf", &__floatsisf},
{"floatunsisf", &__floatunsisf},
{"fixsfsi", &__fixsfsi},
{"fixunssfsi", &__fixunssfsi},
{"adddf3", &__adddf3},
{"subdf3", &__subdf3},
{"muldf3", &__muldf3},
{"divdf3", &__divdf3},
{"floatsidf", &__floatsidf},
{"floatunsidf", &__floatunsidf},
{"floatdidf", &__floatdidf},
{"fixdfsi", &__fixdfsi},
{"fixdfdi", &__fixdfdi},
{"fixunsdfsi", &__fixunsdfsi},
{"clzsi2", &__clzsi2},
{"ctzsi2", &__ctzsi2},
{"udivdi3", &__udivdi3},
{"umoddi3", &__umoddi3},
{"moddi3", &__moddi3},
/* exceptions */
{"_Unwind_Resume", &_Unwind_Resume},
{"__artiq_personality", &__artiq_personality},
{"__artiq_raise", &__artiq_raise},
{"__artiq_reraise", &__artiq_reraise},
{"abort", &ksupport_abort},
/* proxified syscalls */
{"now", &now},
{"watchdog_set", &watchdog_set},
{"watchdog_clear", &watchdog_clear},
{"log", &log},
{"lognonl", &lognonl},
{"send_rpc", &send_rpc},
{"recv_rpc", &recv_rpc},
/* direct syscalls */
{"rtio_get_counter", &rtio_get_counter},
{"ttl_set_o", &ttl_set_o},
{"ttl_set_oe", &ttl_set_oe},
{"ttl_set_sensitivity", &ttl_set_sensitivity},
{"ttl_get", &ttl_get},
{"ttl_clock_set", &ttl_clock_set},
{"dds_init", &dds_init},
{"dds_batch_enter", &dds_batch_enter},
{"dds_batch_exit", &dds_batch_exit},
{"dds_set", &dds_set},
/* end */
{NULL, NULL}
};
/* called by libunwind */
int fprintf(FILE *stream, const char *fmt, ...)
{
struct msg_log request;
request.type = MESSAGE_TYPE_LOG;
request.fmt = fmt;
request.no_newline = 1;
va_start(request.args, fmt);
mailbox_send_and_wait(&request);
va_end(request.args);
return 0;
}
/* called by libunwind */
int dladdr (const void *address, Dl_info *info) {
/* we don't try to resolve names */
return 0;
}
/* called by libunwind */
int dl_iterate_phdr (int (*callback) (struct dl_phdr_info *, size_t, void *), void *data) {
Elf32_Ehdr *ehdr;
struct dl_phdr_info phdr_info;
int retval;
ehdr = (Elf32_Ehdr *)(KERNELCPU_EXEC_ADDRESS - KSUPPORT_HEADER_SIZE);
phdr_info = (struct dl_phdr_info){
.dlpi_addr = 0, /* absolutely linked */
.dlpi_name = "<ksupport>",
.dlpi_phdr = (Elf32_Phdr*) ((intptr_t)ehdr + ehdr->e_phoff),
.dlpi_phnum = ehdr->e_phnum,
};
retval = callback(&phdr_info, sizeof(phdr_info), data);
if(retval)
return retval;
ehdr = (Elf32_Ehdr *)KERNELCPU_PAYLOAD_ADDRESS;
phdr_info = (struct dl_phdr_info){
.dlpi_addr = KERNELCPU_PAYLOAD_ADDRESS,
.dlpi_name = "<kernel>",
.dlpi_phdr = (Elf32_Phdr*) ((intptr_t)ehdr + ehdr->e_phoff),
.dlpi_phnum = ehdr->e_phnum,
};
retval = callback(&phdr_info, sizeof(phdr_info), data);
return retval;
}
static Elf32_Addr resolve_runtime_export(const char *name) {
const struct symbol *sym = runtime_exports;
while(sym->name) {
if(!strcmp(sym->name, name))
return (Elf32_Addr)sym->addr;
++sym;
}
return 0;
}
void exception_handler(unsigned long vect, unsigned long *regs,
unsigned long pc, unsigned long ea);
void exception_handler(unsigned long vect, unsigned long *regs,
unsigned long pc, unsigned long ea)
{
artiq_raise_from_c("InternalError",
"Hardware exception {0} at PC {1}, EA {2}",
vect, pc, ea);
}
int main(void);
int main(void)
{
struct msg_load_request *request = mailbox_receive();
struct msg_load_reply load_reply = {
.type = MESSAGE_TYPE_LOAD_REPLY,
.error = NULL
};
if(request == NULL) {
bridge_main();
while(1);
}
if(request->library != NULL) {
if(!dyld_load(request->library, KERNELCPU_PAYLOAD_ADDRESS,
resolve_runtime_export, request->library_info,
&load_reply.error)) {
mailbox_send(&load_reply);
while(1);
}
}
if(request->run_kernel) {
void (*kernel_init)() = request->library_info->init;
mailbox_send_and_wait(&load_reply);
now = now_init();
kernel_init();
now_save(now);
struct msg_base finished_reply;
finished_reply.type = MESSAGE_TYPE_FINISHED;
mailbox_send_and_wait(&finished_reply);
} else {
mailbox_send(&load_reply);
}
while(1);
}
/* called from __artiq_personality */
void __artiq_terminate(struct artiq_exception *artiq_exn,
struct artiq_backtrace_item *backtrace,
size_t backtrace_size) {
struct msg_exception msg;
msg.type = MESSAGE_TYPE_EXCEPTION;
msg.exception = artiq_exn;
msg.backtrace = backtrace;
msg.backtrace_size = backtrace_size;
mailbox_send(&msg);
while(1);
}
void ksupport_abort() {
artiq_raise_from_c("InternalError", "abort() called; check device log for details",
0, 0, 0);
}
long long int now_init(void)
{
struct msg_base request;
struct msg_now_init_reply *reply;
long long int now;
request.type = MESSAGE_TYPE_NOW_INIT_REQUEST;
mailbox_send_and_wait(&request);
reply = mailbox_wait_and_receive();
if(reply->type != MESSAGE_TYPE_NOW_INIT_REPLY) {
log("Malformed MESSAGE_TYPE_NOW_INIT_REQUEST reply type %d",
reply->type);
while(1);
}
now = reply->now;
mailbox_acknowledge();
if(now < 0) {
rtio_init();
now = rtio_get_counter() + (125000 << RTIO_FINE_TS_WIDTH);
}
return now;
}
void now_save(long long int now)
{
struct msg_now_save request;
request.type = MESSAGE_TYPE_NOW_SAVE;
request.now = now;
mailbox_send_and_wait(&request);
}
int watchdog_set(int ms)
{
struct msg_watchdog_set_request request;
struct msg_watchdog_set_reply *reply;
int id;
request.type = MESSAGE_TYPE_WATCHDOG_SET_REQUEST;
request.ms = ms;
mailbox_send_and_wait(&request);
reply = mailbox_wait_and_receive();
if(reply->type != MESSAGE_TYPE_WATCHDOG_SET_REPLY) {
log("Malformed MESSAGE_TYPE_WATCHDOG_SET_REQUEST reply type %d",
reply->type);
while(1);
}
id = reply->id;
mailbox_acknowledge();
return id;
}
void watchdog_clear(int id)
{
struct msg_watchdog_clear request;
request.type = MESSAGE_TYPE_WATCHDOG_CLEAR;
request.id = id;
mailbox_send_and_wait(&request);
}
void send_rpc(int service, const char *tag, ...)
{
struct msg_rpc_send request;
request.type = MESSAGE_TYPE_RPC_SEND;
request.service = service;
request.tag = tag;
va_start(request.args, tag);
mailbox_send_and_wait(&request);
va_end(request.args);
}
int recv_rpc(void *slot) {
struct msg_rpc_recv_request request;
struct msg_rpc_recv_reply *reply;
request.type = MESSAGE_TYPE_RPC_RECV_REQUEST;
request.slot = slot;
mailbox_send_and_wait(&request);
reply = mailbox_wait_and_receive();
if(reply->type != MESSAGE_TYPE_RPC_RECV_REPLY) {
log("Malformed MESSAGE_TYPE_RPC_RECV_REQUEST reply type %d",
reply->type);
while(1);
}
if(reply->exception) {
struct artiq_exception exception;
memcpy(&exception, reply->exception,
sizeof(struct artiq_exception));
mailbox_acknowledge();
__artiq_raise(&exception);
} else {
int alloc_size = reply->alloc_size;
mailbox_acknowledge();
return alloc_size;
}
}
void lognonl(const char *fmt, ...)
{
struct msg_log request;
request.type = MESSAGE_TYPE_LOG;
request.fmt = fmt;
request.no_newline = 1;
va_start(request.args, fmt);
mailbox_send_and_wait(&request);
va_end(request.args);
}
void log(const char *fmt, ...)
{
struct msg_log request;
request.type = MESSAGE_TYPE_LOG;
request.fmt = fmt;
request.no_newline = 0;
va_start(request.args, fmt);
mailbox_send_and_wait(&request);
va_end(request.args);
}