#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); /* 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_init", &now_init}, {"now_save", &now_save}, {"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); kernel_init(); 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); }