/* * Read memory statistics data */ static void get_paging_data(struct paging_data *pd) { static const char *key_pgpgin = "pgpgin"; static const char *key_nr_free_pages = "nr_free_pages"; static const char parse_error_msg[] = "error parsing /proc/vmstat"; char *cp, *xp; bool found_pgpgin = false; bool found_nr_free_pages = false; int nfound = 0; const int need_found = 2; pd->ts = getnow(); pd->mem_pages = sysconf(_SC_PHYS_PAGES); if (pd->mem_pages <= 0) fatal_msg("unable to get system memory size"); read_whole_file("/proc/vmstat", &vmstat, &vmstat_size, 4096); for (cp = vmstat; *cp != '\0';) { if (is_key(&cp, key_pgpgin)) { if (!consume_umax(&cp, &pd->pgpgin)) fatal_msg(parse_error_msg); if (!found_pgpgin) { found_pgpgin = true; if (need_found == ++nfound) break; } } else if (is_key(&cp, key_nr_free_pages)) { if (!consume_umax(&cp, &pd->nr_free_pages)) fatal_msg(parse_error_msg); if (!found_nr_free_pages) { found_nr_free_pages = true; if (need_found == ++nfound) break; } } else { xp = strchr(cp, '\n'); if (!xp) break; cp = xp + 1; } } if (need_found != nfound) fatal_msg(parse_error_msg); }
static void _handle_touch(struct cxl_afu_h *afu, uint64_t addr, uint8_t size) { uint8_t buffer; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_handle_touch"); if (!_testmemaddr((uint8_t *) addr)) { if (_handle_dsi(afu, addr) < 0) { perror("DSI Failure"); return; } DPRINTF("TOUCH of invalid addr @ 0x%016" PRIx64 "\n", addr); buffer = (uint8_t) PSLSE_MEM_FAILURE; if (put_bytes_silent(afu->fd, 1, &buffer) != 1) { afu->opened = 0; afu->attached = 0; } return; } buffer = PSLSE_MEM_SUCCESS; if (put_bytes_silent(afu->fd, 1, &buffer) != 1) { afu->opened = 0; afu->attached = 0; } DPRINTF("TOUCH of addr @ 0x%016" PRIx64 "\n", addr); }
static void _handle_read(struct cxl_afu_h *afu, uint64_t addr, uint8_t size) { uint8_t buffer[MAX_LINE_CHARS]; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_handle_read"); if (!_testmemaddr((uint8_t *) addr)) { if (_handle_dsi(afu, addr) < 0) { perror("DSI Failure"); return; } DPRINTF("READ from invalid addr @ 0x%016" PRIx64 "\n", addr); buffer[0] = (uint8_t) PSLSE_MEM_FAILURE; if (put_bytes_silent(afu->fd, 1, buffer) != 1) { afu->opened = 0; afu->attached = 0; } return; } buffer[0] = PSLSE_MEM_SUCCESS; memcpy(&(buffer[1]), (void *)addr, size); if (put_bytes_silent(afu->fd, size + 1, buffer) != size + 1) { afu->opened = 0; afu->attached = 0; } DPRINTF("READ from addr @ 0x%016" PRIx64 "\n", addr); }
static void _handle_ack(struct cxl_afu_h *afu) { uint8_t data[sizeof(uint64_t)]; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_handle_ack"); DPRINTF("MMIO ACK\n"); if ((afu->mmio.type == PSLSE_MMIO_READ64)| (afu->mmio.type == PSLSE_MMIO_EBREAD)) { if (get_bytes_silent(afu->fd, sizeof(uint64_t), data, 1000, 0) < 0) { warn_msg("Socket failure getting MMIO Ack"); _all_idle(afu); afu->mmio.data = 0xFEEDB00FFEEDB00FL; } else { memcpy(&(afu->mmio.data), data, sizeof(uint64_t)); afu->mmio.data = ntohll(afu->mmio.data); } } if (afu->mmio.type == PSLSE_MMIO_READ32) { if (get_bytes_silent(afu->fd, sizeof(uint32_t), data, 1000, 0) < 0) { warn_msg("Socket failure getting MMIO Read 32 data"); afu->mmio.data = 0xFEEDB00FL; _all_idle(afu); } else { memcpy(&(afu->mmio.data), data, sizeof(uint32_t)); debug_msg("KEM:0x%08x", afu->mmio.data); afu->mmio.data = ntohl(afu->mmio.data); debug_msg("KEM:0x%08x", afu->mmio.data); } } afu->mmio.state = LIBCXL_REQ_IDLE; }
static int _handle_dsi(struct cxl_afu_h *afu, uint64_t addr) { uint16_t size; int i; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_handle_dsi"); // Only track a single DSI at a time pthread_mutex_lock(&(afu->event_lock)); i = 0; while (afu->events[i] != NULL) { if (afu->events[i]->header.type == CXL_EVENT_DATA_STORAGE) { pthread_mutex_unlock(&(afu->event_lock)); return 0; } ++i; } assert(i < EVENT_QUEUE_MAX); size = sizeof(struct cxl_event_header) + sizeof(struct cxl_event_data_storage); afu->events[i] = (struct cxl_event *)calloc(1, size); afu->events[i]->header.type = CXL_EVENT_DATA_STORAGE; afu->events[i]->header.size = size; afu->events[i]->header.process_element = afu->context; afu->events[i]->fault.addr = addr & FOURK_MASK; afu->events[i]->fault.dsisr = DSISR; do { i = write(afu->pipe[1], &(afu->events[i]->header.type), 1); } while ((i == 0) || (errno == EINTR)); pthread_mutex_unlock(&(afu->event_lock)); return i; }
static __inline__ void *safe_calloc(unsigned int size, char *file, unsigned int line) { void *res = calloc(1, size); if (res == NULL) fatal_msg("CALLOC failed", file, line); return res; }
static void _mmio_read(struct cxl_afu_h *afu) { uint8_t *buffer; uint32_t addr; int size, offset; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_mmio_read"); size = 1 + sizeof(addr); buffer = (uint8_t *) malloc(size); buffer[0] = afu->mmio.type; offset = 1; addr = htonl(afu->mmio.addr); memcpy((char *)&(buffer[offset]), (char *)&addr, sizeof(addr)); if (put_bytes_silent(afu->fd, size, buffer) != size) { warn_msg("_mmio_read: put_bytes_silent failed"); free(buffer); close_socket(&(afu->fd)); afu->opened = 0; afu->attached = 0; afu->mmio.state = LIBCXL_REQ_IDLE; afu->mmio.data = 0xFEEDB00FFEEDB00FL; return; } free(buffer); afu->mmio.state = LIBCXL_REQ_PENDING; }
/* * Commit current xenstore transaction. * * Returns: * XSTS_OK success * XSTS_RETRY retry the transaction * XSTS_NORETRY out of retry limit (message logged) * XSTS_FAIL commit failed (message logged) */ static XsTransactionStatus commit_xs(int* p_nretries) { if (xst == XS_TRANSACTION_NULL) fatal_msg("bug: commit_xs outside of a transaction"); if (xs_transaction_end(xs, xst, FALSE)) { debug_msg(15, "committed transaction"); xst = XS_TRANSACTION_NULL; return XSTS_OK; } xst = XS_TRANSACTION_NULL; if (errno == EAGAIN) { if (++(*p_nretries) > max_xs_retries) { error_perror("unable to write xenstore (transaction retry limit exceeded)"); return XSTS_NORETRY; } retry_wait(*p_nretries); debug_msg(2, "restarting xenstore transaction"); return XSTS_RETRY; } else { error_perror("unable to write xenstore (xs_transaction_end)"); return XSTS_FAIL; } }
static void _pslse_attach(struct cxl_afu_h *afu) { uint8_t *buffer; uint64_t *wed_ptr; int size, offset; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_pslse_attach"); size = 1 + sizeof(uint64_t); buffer = (uint8_t *) malloc(size); buffer[0] = PSLSE_ATTACH; offset = 1; wed_ptr = (uint64_t *) & (buffer[offset]); *wed_ptr = htonll(afu->attach.wed); if (put_bytes_silent(afu->fd, size, buffer) != size) { free(buffer); close_socket(&(afu->fd)); afu->opened = 0; afu->attached = 0; afu->attach.state = LIBCXL_REQ_IDLE; return; } free(buffer); afu->attach.state = LIBCXL_REQ_PENDING; }
/* * Process expected signals */ static void handle_signals(struct pollfd *pollfds, bool *p_recheck_time) { struct signalfd_siginfo fdsi; ssize_t sz; /* SIGTERM - exit gracefully */ if (pollfds[NPFD_SIGTERM].revents & (POLLIN|POLLPRI)) { shutdown_xs(); notice_msg("terminating..."); exit(EXIT_SUCCESS); } /* SIGHUP - reload configuration */ if (pollfds[NPFD_SIGHUP].revents & (POLLIN|POLLPRI)) { sz = read(fd_sighup, &fdsi, sizeof(fdsi)); if (sz < 0) fatal_perror("read signalfd"); if (sz != sizeof(fdsi)) fatal_msg("read signalfd"); /* reload configuration -- currently none for memprobed */ if (p_recheck_time) *p_recheck_time = true; } }
static void _mmio_write32(struct cxl_afu_h *afu) { uint8_t *buffer; uint32_t data; uint32_t addr; int size, offset; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_mmio_write32"); size = 1 + sizeof(addr) + sizeof(data); buffer = (uint8_t *) malloc(size); buffer[0] = PSLSE_MMIO_WRITE32; offset = 1; addr = htonl(afu->mmio.addr); memcpy((char *)&(buffer[offset]), (char *)&addr, sizeof(addr)); offset += sizeof(addr); data = htonl(afu->mmio.data); memcpy((char *)&(buffer[offset]), (char *)&data, sizeof(data)); if (put_bytes_silent(afu->fd, size, buffer) != size) { free(buffer); close_socket(&(afu->fd)); afu->opened = 0; afu->attached = 0; afu->mmio.state = LIBCXL_REQ_IDLE; return; } free(buffer); afu->mmio.state = LIBCXL_REQ_PENDING; }
static void _mmio_map(struct cxl_afu_h *afu) { uint8_t *buffer; uint32_t *flags_ptr; uint32_t flags; int size; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_mmio_map"); size = 1 + sizeof(uint32_t); buffer = (uint8_t *) malloc(size); buffer[0] = PSLSE_MMIO_MAP; flags = (uint32_t) afu->mmio.data; flags_ptr = (uint32_t *) & (buffer[1]); *flags_ptr = htonl(flags); if (put_bytes_silent(afu->fd, size, buffer) != size) { free(buffer); close_socket(&(afu->fd)); afu->opened = 0; afu->attached = 0; afu->mmio.state = LIBCXL_REQ_IDLE; return; } free(buffer); afu->mmio.state = LIBCXL_REQ_PENDING; }
/* * Verify we are running under Xen, * and not in the root domain */ static void verify_hypervisor(void) { FILE *fp = NULL; char buf[256]; char *p; const static char root_uuid[] = "00000000-0000-0000-0000-000000000000"; const char *rp; /* * Check that file /sys/hypervisor/type is present * and contains "xen" */ if (access("/sys/hypervisor/type", F_OK) == -1 && (errno == ENOENT || errno == ENOTDIR)) fatal_msg("not running under a hypervisor"); fp = fopen("/sys/hypervisor/type", "r"); if (fp == NULL || NULL == fgets(buf, countof(buf), fp)) fatal_msg("unable to read /sys/hypervisor/type"); buf[countof(buf) - 1] = '\0'; p = strchr(buf, '\n'); if (p) *p = '\0'; if (0 != strcasecmp(buf, "xen")) fatal_msg("hypervisor is not Xen"); fclose(fp); /* * Read Xen domain UUID from /sys/hypervisor/uuid * and check it is not the root domain */ fp = fopen("/sys/hypervisor/uuid", "r"); if (fp == NULL || NULL == fgets(buf, countof(buf), fp)) fatal_msg("unable to read /sys/hypervisor/uuid"); buf[countof(buf) - 1] = '\0'; p = strchr(buf, '\n'); if (p) *p = '\0'; if (0 == strcmp(buf, root_uuid)) fatal_msg("may run only in a VM, not root domain"); fclose(fp); if (strlen(buf) != strlen(root_uuid) /* || strlen(buf) != UUID_STRING_SIZE - 1 */) fatal_msg("unexpected domain uuid"); for (p = buf, rp = root_uuid; *rp; p++, rp++) { if (*rp == '-' && *p == '-') continue; if (isxdigit(*rp) && isxdigit(*p)) continue; fatal_msg("unexpected domain uuid"); } // strcpy(vm_uuid, buf); }
static void _all_idle(struct cxl_afu_h *afu) { if (!afu) fatal_msg("NULL afu passed to libcxl.c:_all_idle"); afu->int_req.state = LIBCXL_REQ_IDLE; afu->open.state = LIBCXL_REQ_IDLE; afu->attach.state = LIBCXL_REQ_IDLE; afu->mmio.state = LIBCXL_REQ_IDLE; afu->mapped = 0; afu->attached = 0; afu->opened = 0; }
static int _handle_afu_error(struct cxl_afu_h *afu) { uint64_t error; uint16_t size; uint8_t data[sizeof(error)]; int i; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_handle_afu_error"); DPRINTF("AFU ERROR\n"); if (get_bytes_silent(afu->fd, sizeof(error), data, 1000, 0) < 0) { warn_msg("Socket failure getting AFU ERROR"); _all_idle(afu); return -1; } memcpy(&error, data, sizeof(error)); error = ntohll(error); // Only track a single AFU error at a time pthread_mutex_lock(&(afu->event_lock)); i = 0; while (afu->events[i] != NULL) { if (afu->events[i]->header.type == CXL_EVENT_AFU_ERROR) { pthread_mutex_unlock(&(afu->event_lock)); return 0; } ++i; } assert(i < EVENT_QUEUE_MAX); size = sizeof(struct cxl_event_header) + sizeof(struct cxl_event_afu_error); afu->events[i] = (struct cxl_event *)calloc(1, size); afu->events[i]->header.type = CXL_EVENT_AFU_ERROR; afu->events[i]->header.size = size; afu->events[i]->header.process_element = afu->context; afu->events[i]->afu_error.error = error; do { i = write(afu->pipe[1], &(afu->events[i]->header.type), 1); } while ((i == 0) || (errno == EINTR)); pthread_mutex_unlock(&(afu->event_lock)); return i; }
/* * Select preferred interval clock among available ones */ static void select_clk_id(void) { struct timespec ts; clk_id = CLOCK_BOOTTIME; if (0 == clock_gettime(clk_id, &ts)) return; clk_id = CLOCK_MONOTONIC_RAW; if (0 == clock_gettime(clk_id, &ts)) return; clk_id = CLOCK_MONOTONIC; if (0 == clock_gettime(clk_id, &ts)) return; fatal_msg("unable to select clk_id"); }
static int _handle_interrupt(struct cxl_afu_h *afu) { uint16_t size, irq; uint8_t data[sizeof(irq)]; int i; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_handle_interrupt"); DPRINTF("AFU INTERRUPT\n"); if (get_bytes_silent(afu->fd, sizeof(irq), data, 1000, 0) < 0) { warn_msg("Socket failure getting IRQ"); _all_idle(afu); return -1; } memcpy(&irq, data, sizeof(irq)); irq = ntohs(irq); // Only track a single interrupt at a time pthread_mutex_lock(&(afu->event_lock)); i = 0; while (afu->events[i] != NULL) { if (afu->events[i]->header.type == CXL_EVENT_AFU_INTERRUPT) { pthread_mutex_unlock(&(afu->event_lock)); return 0; } ++i; } assert(i < EVENT_QUEUE_MAX); size = sizeof(struct cxl_event_header) + sizeof(struct cxl_event_afu_interrupt); afu->events[i] = (struct cxl_event *)calloc(1, size); afu->events[i]->header.type = CXL_EVENT_AFU_INTERRUPT; afu->events[i]->header.size = size; afu->events[i]->header.process_element = afu->context; afu->events[i]->irq.irq = irq; do { i = write(afu->pipe[1], &(afu->events[i]->header.type), 1); } while ((i == 0) || (errno == EINTR)); pthread_mutex_unlock(&(afu->event_lock)); return i; }
/* * Start XenStore transaction. * If successful, return @true. * On error, return @false and log error message. . */ static bool begin_xs(void) { int nretries = 0; if (xst != XS_TRANSACTION_NULL) fatal_msg("bug: begin_xs inside a transaction"); for (;;) { xst = xs_transaction_start(xs); if (xst != XS_TRANSACTION_NULL) break; /* * ENOSPC means too many concurrent transactions from the domain */ if (errno == ENOSPC) { if (++nretries > max_xs_retries) { error_perror("unable to start xenstore transaction (retry limit exceeded)"); break; } retry_wait(nretries); debug_msg(2, "retrying to start xenstore transaction"); } else { error_perror("unable to start xenstore transaction"); break; } } if (xst != XS_TRANSACTION_NULL) { debug_msg(15, "started transaction"); return true; } else { return false; } }
/* * Socket file with the same name already exists. * If another instance of membalanced is already running, abort. * Otherwise delete leftover file, and let the caller retry again. */ static void on_addrinuse(const struct sockaddr_un& addr) { int fd; int rc; DO_RESTARTABLE(fd, socket(AF_UNIX, SOCK_STREAM, 0)); if (fd == -1) fatal_perror("unable to create RPC socket"); DO_RESTARTABLE(rc, connect(fd, (struct sockaddr*)&addr, sizeof addr)); if (rc == 0) fatal_msg("membalanced is already running and owns RPC socket"); if (errno != ECONNREFUSED) fatal_perror("socket file %s in a bad state", socket_path); /* socket exists, but no one is lisening on it */ if (unlink(socket_path) && errno != ENOENT) fatal_perror("unable to delete socket file %s", socket_path); }
static void _release_adapters(struct cxl_adapter_h *adapter) { struct cxl_adapter_h *current; uint8_t rc = PSLSE_DETACH; if (!adapter) fatal_msg("NULL adapter passed to libcxl.c:_release_adapters"); _release_afus(adapter->afu_list); current = adapter; while (current != NULL) { adapter = current; current = current->_next; // Disconnect from PSLSE if (adapter->fd) { put_bytes_silent(adapter->fd, 1, &rc); close_socket(&(adapter->fd)); } free(adapter->id); free(adapter); } }
/* * Log/print error message (incl. errno) and terminate */ static void fatal_perror(const char *fmt, ...) /* __noreturn__ __format_printf__ */ { char *errno_msg; char errno_msg_buf[128]; char msg[512]; int size = 0; va_list ap; errno_msg = strerror_r(errno, errno_msg_buf, countof(errno_msg_buf)); strcpy(msg, "fatal error: "); size = strlen(msg); va_start(ap, fmt); vsnprintf(msg + size, countof(msg) - size, fmt, ap); va_end(ap); size = strlen(msg); snprintf(msg + size, countof(msg) - size, ": %s", errno_msg); fatal_msg("%s", msg); }
static void _req_max_int(struct cxl_afu_h *afu) { uint8_t *buffer; int size; uint16_t value; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_req_max_int"); size = 1 + sizeof(uint16_t); buffer = (uint8_t *) malloc(size); buffer[0] = PSLSE_MAX_INT; value = htons(afu->int_req.max); memcpy((char *)&(buffer[1]), (char *)&value, sizeof(uint16_t)); if (put_bytes_silent(afu->fd, size, buffer) != size) { free(buffer); close_socket(&(afu->fd)); afu->int_req.max = 0; _all_idle(afu); return; } free(buffer); afu->int_req.state = LIBCXL_REQ_PENDING; }
// Send a randomly selected pending response back to AFU void handle_response(struct cmd *cmd) { struct cmd_event **head; struct cmd_event *event; struct client *client; int rc; // Select a random pending response (or none) client = NULL; head = &cmd->list; while (*head != NULL) { // Fast track error responses if (((*head)->resp == PSL_RESPONSE_PAGED) || ((*head)->resp == PSL_RESPONSE_NRES) || ((*head)->resp == PSL_RESPONSE_NLOCK) || ((*head)->resp == PSL_RESPONSE_FAILED) || ((*head)->resp == PSL_RESPONSE_FLUSHED)) { event = *head; goto drive_resp; } if (((*head)->state == MEM_DONE) && !allow_reorder(cmd->parms)) { break; } head = &((*head)->_next); } // Randomly decide not to drive response yet event = *head; if ((event == NULL) || ((event->client_state == CLIENT_VALID) && !allow_resp(cmd->parms))) { return; } // Test for client disconnect if ((event == NULL) || ((client = _get_client(cmd, event)) == NULL)) return; // Send response, remove command from list and free memory if ((event->resp == PSL_RESPONSE_PAGED) || (event->resp == PSL_RESPONSE_AERROR) || (event->resp == PSL_RESPONSE_DERROR)) { client->flushing = FLUSH_FLUSHING; _update_pending_resps(cmd, PSL_RESPONSE_FLUSHED); } drive_resp: // Check for pending buffer activity if (event == cmd->buffer_read) { fatal_msg("Driving response when buffer read still active"); _print_event(event); assert(event != cmd->buffer_read); } rc = psl_response(cmd->afu_event, event->tag, event->resp, 1, 0, 0); if (rc == PSL_SUCCESS) { debug_msg("%s:RESPONSE tag=0x%02x code=0x%x", cmd->afu_name, event->tag, event->resp); debug_cmd_response(cmd->dbg_fp, cmd->dbg_id, event->tag); if ((client != NULL) && (event->command == PSL_COMMAND_RESTART)) client->flushing = FLUSH_NONE; *head = event->_next; free(event->data); free(event->parity); free(event); cmd->credits++; } }
static void *_psl_loop(void *ptr) { struct cxl_afu_h *afu = (struct cxl_afu_h *)ptr; uint8_t buffer[MAX_LINE_CHARS]; uint8_t size; uint64_t addr; uint16_t value; uint32_t lvalue; int rc; if (!afu) fatal_msg("NULL afu passed to libcxl.c:_psl_loop"); afu->opened = 1; while (afu->opened) { _delay_1ms(); // Send any requests to PSLSE over socket if (afu->int_req.state == LIBCXL_REQ_REQUEST) _req_max_int(afu); if (afu->attach.state == LIBCXL_REQ_REQUEST) _pslse_attach(afu); if (afu->mmio.state == LIBCXL_REQ_REQUEST) { switch (afu->mmio.type) { case PSLSE_MMIO_MAP: _mmio_map(afu); break; case PSLSE_MMIO_WRITE64: _mmio_write64(afu); break; case PSLSE_MMIO_WRITE32: _mmio_write32(afu); break; case PSLSE_MMIO_EBREAD: case PSLSE_MMIO_READ64: case PSLSE_MMIO_READ32: /*fall through */ _mmio_read(afu); break; default: break; } } // Process socket input from PSLSE rc = bytes_ready(afu->fd, 1000, 0); if (rc == 0) continue; if (rc < 0) { warn_msg("Socket failure testing bytes_ready"); _all_idle(afu); break; } if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) { warn_msg("Socket failure getting PSL event"); _all_idle(afu); break; } DPRINTF("PSL EVENT\n"); switch (buffer[0]) { case PSLSE_OPEN: if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) { warn_msg("Socket failure getting OPEN context"); _all_idle(afu); break; } afu->context = (uint16_t) buffer[0]; afu->open.state = LIBCXL_REQ_IDLE; break; case PSLSE_ATTACH: afu->attach.state = LIBCXL_REQ_IDLE; break; case PSLSE_DETACH: info_msg("detach response from from pslse"); afu->mapped = 0; afu->attached = 0; afu->opened = 0; afu->open.state = LIBCXL_REQ_IDLE; afu->attach.state = LIBCXL_REQ_IDLE; afu->mmio.state = LIBCXL_REQ_IDLE; afu->int_req.state = LIBCXL_REQ_IDLE; break; case PSLSE_MAX_INT: size = sizeof(uint16_t); if (get_bytes_silent(afu->fd, size, buffer, 1000, 0) < 0) { warn_msg ("Socket failure getting max interrupt acknowledge"); _all_idle(afu); break; } memcpy((char *)&value, (char *)buffer, sizeof(uint16_t)); afu->irqs_max = ntohs(value); afu->int_req.state = LIBCXL_REQ_IDLE; break; case PSLSE_QUERY: { size = sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t); if (get_bytes_silent(afu->fd, size, buffer, 1000, 0) < 0) { warn_msg("Socket failure getting PSLSE query"); _all_idle(afu); break; } memcpy((char *)&value, (char *)&(buffer[0]), 2); afu->irqs_min = (long)(value); memcpy((char *)&value, (char *)&(buffer[2]), 2); afu->irqs_max = (long)(value); memcpy((char *)&value, (char *)&(buffer[4]), 2); afu->modes_supported = (long)(value); memcpy((char *)&value, (char *)&(buffer[6]), 8); afu->mmio_len = (long)(value); memcpy((char *)&value, (char *)&(buffer[14]), 8); afu->mmio_off = (long)(value); memcpy((char *)&value, (char *)&(buffer[22]), 8); //afu->eb_len = (long)ntohll(value); afu->eb_len = (long)(value); memcpy((char *)&value, (char *)&(buffer[30]), 2); afu->cr_device = (long)ntohs(value); memcpy((char *)&value, (char *)&(buffer[32]), 2); afu->cr_vendor = (long)ntohs(value); memcpy((char *)&lvalue, (char *)&(buffer[34]), 4); afu->cr_class = ntohl(lvalue); //no better place to put this right now afu->prefault_mode = CXL_PREFAULT_MODE_NONE; break; } case PSLSE_MEMORY_READ: DPRINTF("AFU MEMORY READ\n"); if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) { warn_msg ("Socket failure getting memory read size"); _all_idle(afu); break; } size = (uint8_t) buffer[0]; if (get_bytes_silent(afu->fd, sizeof(uint64_t), buffer, -1, 0) < 0) { warn_msg ("Socket failure getting memory read addr"); _all_idle(afu); break; } memcpy((char *)&addr, (char *)buffer, sizeof(uint64_t)); addr = ntohll(addr); _handle_read(afu, addr, size); break; case PSLSE_MEMORY_WRITE: DPRINTF("AFU MEMORY WRITE\n"); if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) { warn_msg ("Socket failure getting memory write size"); _all_idle(afu); break; } size = (uint8_t) buffer[0]; if (get_bytes_silent(afu->fd, sizeof(uint64_t), buffer, -1, 0) < 0) { _all_idle(afu); break; } memcpy((char *)&addr, (char *)buffer, sizeof(uint64_t)); addr = ntohll(addr); if (get_bytes_silent(afu->fd, size, buffer, 1000, 0) < 0) { warn_msg ("Socket failure getting memory write data"); _all_idle(afu); break; } _handle_write(afu, addr, size, buffer); break; case PSLSE_MEMORY_TOUCH: DPRINTF("AFU MEMORY TOUCH\n"); if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) { warn_msg ("Socket failure getting memory touch size"); _all_idle(afu); break; } size = buffer[0]; if (get_bytes_silent(afu->fd, sizeof(uint64_t), buffer, -1, 0) < 0) { warn_msg ("Socket failure getting memory touch addr"); _all_idle(afu); break; } memcpy((char *)&addr, (char *)buffer, sizeof(uint64_t)); addr = ntohll(addr); _handle_touch(afu, addr, size); break; case PSLSE_MMIO_ACK: _handle_ack(afu); break; case PSLSE_INTERRUPT: if (_handle_interrupt(afu) < 0) { perror("Interrupt Failure"); goto psl_fail; } break; case PSLSE_AFU_ERROR: if (_handle_afu_error(afu) < 0) { perror("AFU ERROR Failure"); goto psl_fail; } break; default: break; } } psl_fail: afu->attached = 0; pthread_exit(NULL); }
/* * Start built-in RPC server */ void start_rcmd_server(void) { struct sockaddr_un addr; int rc; if (sock != -1) return; /* ensure socket directory exists */ make_membalance_rundir(); for (;;) { /* create socket */ if (sock == -1) { DO_RESTARTABLE(sock, socket(AF_UNIX, SOCK_STREAM, 0)); if (sock == -1) fatal_perror("unable to create RPC socket"); } /* build address block */ if (strlen(socket_path) >= sizeof(addr.sun_path)) fatal_msg("RPC socket path is too long"); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path, socket_path); /* try to bind socket to a name (and create socket file in file system) */ DO_RESTARTABLE(rc, bind(sock, (struct sockaddr*)&addr, sizeof addr)); if (rc != 0) { /* socket file already exists? */ if (errno == EADDRINUSE) { on_addrinuse(addr); continue; } else { fatal_perror("unable to bind RPC socket to %s", socket_path); } } /* successfully created socket file */ sock_unlink = true; if (chmod(socket_path, S_IRWXU)) { stop_rcmd_server(); fatal_perror("unable to set protection on socket file %s", socket_path); } DO_RESTARTABLE(rc, listen(sock, SOMAXCONN)); if (rc == 0) break; stop_rcmd_server(); if (errno == EADDRINUSE) { on_addrinuse(addr); continue; } else { fatal_perror("unable to listen on socket file %s", socket_path); } } if (!svc_registered) { if (!svc_register(NULL, RCMD_MEMBALANCED, RCMD_MEMBALANCED_V1, rcmd_membalanced_1, 0)) fatal_msg("unable to register RPC server (svc_register)"); svc_registered = true; } debug_msg(7, "registered RPC server"); }
static struct cxl_afu_h *_pslse_open(int *fd, uint16_t afu_map, uint8_t major, uint8_t minor, char afu_type) { struct cxl_afu_h *afu; uint8_t *buffer; uint16_t position; if (!fd) fatal_msg("NULL fd passed to libcxl.c:_pslse_open"); position = 0x8000; position >>= 4 * major; position >>= minor; if ((afu_map & position) != position) { warn_msg("open:AFU not in system"); close_socket(fd); errno = ENODEV; return NULL; } // Create struct for AFU afu = _new_afu(afu_map, position, *fd); if (afu == NULL) return NULL; buffer = (uint8_t *) calloc(1, MAX_LINE_CHARS); buffer[0] = (uint8_t) PSLSE_OPEN; buffer[1] = afu->dbg_id; buffer[2] = afu_type; afu->fd = *fd; if (put_bytes_silent(afu->fd, 3, buffer) != 3) { warn_msg("open:Failed to write to socket"); free(buffer); goto open_fail; } free(buffer); afu->_head = afu; afu->adapter = major; afu->id = (char *)malloc(7); afu->open.state = LIBCXL_REQ_PENDING; // Start thread if (pthread_create(&(afu->thread), NULL, _psl_loop, afu)) { perror("pthread_create"); close_socket(&(afu->fd)); goto open_fail; } // Wait for open acknowledgement while (afu->open.state != LIBCXL_REQ_IDLE) /*infinite loop */ _delay_1ms(); if (!afu->opened) { pthread_join(afu->thread, NULL); goto open_fail; } sprintf(afu->id, "afu%d.%d", major, minor); return afu; open_fail: pthread_mutex_destroy(&(afu->event_lock)); free(afu); errno = ENODEV; return NULL; }
/* * Commit a pseudo-transaction that involves just one read or write operation */ static XsTransactionStatus commit_singleop_xs(int* p_nretries) { if (xst != XS_TRANSACTION_NULL) fatal_msg("bug: commit_singleop_xs inside a real transaction"); return XSTS_OK; }
/* * Abort a pseudo-transaction that involves just one read or write operation */ static void abort_singleop_xs(void) { if (xst != XS_TRANSACTION_NULL) fatal_msg("bug: abort_singleop_xs inside a real transaction"); }
/* * Begin a pseudo-transaction that involves just one read or write operation */ static bool begin_singleop_xs(void) { if (xst != XS_TRANSACTION_NULL) fatal_msg("bug: begin_singleop_xs inside a transaction"); return true; }
/* * Log/print "out of memory" message and terminate */ static void out_of_memory(void) /* __noreturn__ __format_printf__ */ { fatal_msg("out of memory"); }