#include #include #include #include #include #include #include #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 = "", .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 = "", .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); }