int rte_ivshmem_metadata_cmdline_generate(char *buffer, unsigned size, const char *name) { const struct memseg_cache_entry * ms_cache, *entry; struct ivshmem_config * config; char cmdline[IVSHMEM_QEMU_CMDLINE_BUFSIZE], *cmdline_ptr; char cfg_file_path[PATH_MAX]; unsigned remaining_len, tmplen, iter; uint64_t shared_mem_size, zero_size, total_size; if (buffer == NULL || name == NULL) return -1; config = get_config_by_name(name); if (config == NULL) { RTE_LOG(ERR, EAL, "Config %s not found!\n", name); return -1; } rte_spinlock_lock(&config->sl); /* prepare metadata file path */ snprintf(cfg_file_path, sizeof(cfg_file_path), IVSHMEM_CONFIG_FILE_FMT, config->metadata->name); ms_cache = config->memseg_cache; cmdline_ptr = cmdline; remaining_len = sizeof(cmdline); shared_mem_size = 0; iter = 0; while ((ms_cache[iter].len != 0) && (iter < RTE_DIM(config->metadata->entry))) { entry = &ms_cache[iter]; /* Offset and sizes within the current pathname */ tmplen = snprintf(cmdline_ptr, remaining_len, IVSHMEM_QEMU_CMD_FD_FMT, entry->filepath, entry->offset, entry->len); shared_mem_size += entry->len; cmdline_ptr = RTE_PTR_ADD(cmdline_ptr, tmplen); remaining_len -= tmplen; if (remaining_len == 0) { RTE_LOG(ERR, EAL, "Command line too long!\n"); rte_spinlock_unlock(&config->sl); return -1; } iter++; } total_size = rte_align64pow2(shared_mem_size + METADATA_SIZE_ALIGNED); zero_size = total_size - shared_mem_size - METADATA_SIZE_ALIGNED; /* add /dev/zero to command-line to fill the space */ tmplen = snprintf(cmdline_ptr, remaining_len, IVSHMEM_QEMU_CMD_FD_FMT, "/dev/zero", (uint64_t)0x0, zero_size); cmdline_ptr = RTE_PTR_ADD(cmdline_ptr, tmplen); remaining_len -= tmplen; if (remaining_len == 0) { RTE_LOG(ERR, EAL, "Command line too long!\n"); rte_spinlock_unlock(&config->sl); return -1; } /* add metadata file to the end of command-line */ tmplen = snprintf(cmdline_ptr, remaining_len, IVSHMEM_QEMU_CMD_FD_FMT, cfg_file_path, (uint64_t)0x0, METADATA_SIZE_ALIGNED); cmdline_ptr = RTE_PTR_ADD(cmdline_ptr, tmplen); remaining_len -= tmplen; if (remaining_len == 0) { RTE_LOG(ERR, EAL, "Command line too long!\n"); rte_spinlock_unlock(&config->sl); return -1; } /* if current length of the command line is bigger than the buffer supplied * by the user, or if command-line is bigger than what IVSHMEM accepts */ if ((sizeof(cmdline) - remaining_len) > size) { RTE_LOG(ERR, EAL, "Buffer is too short!\n"); rte_spinlock_unlock(&config->sl); return -1; } /* complete the command-line */ snprintf(buffer, size, IVSHMEM_QEMU_CMD_LINE_HEADER_FMT, total_size >> 20, cmdline); rte_spinlock_unlock(&config->sl); return 0; }
static int vfio_spapr_dma_map(int vfio_container_fd) { const struct rte_memseg *ms = rte_eal_get_physmem_layout(); int i, ret; struct vfio_iommu_spapr_register_memory reg = { .argsz = sizeof(reg), .flags = 0 }; struct vfio_iommu_spapr_tce_info info = { .argsz = sizeof(info), }; struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create), }; struct vfio_iommu_spapr_tce_remove remove = { .argsz = sizeof(remove), }; /* query spapr iommu info */ ret = ioctl(vfio_container_fd, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info); if (ret) { RTE_LOG(ERR, EAL, " cannot get iommu info, " "error %i (%s)\n", errno, strerror(errno)); return -1; } /* remove default DMA of 32 bit window */ remove.start_addr = info.dma32_window_start; ret = ioctl(vfio_container_fd, VFIO_IOMMU_SPAPR_TCE_REMOVE, &remove); if (ret) { RTE_LOG(ERR, EAL, " cannot remove default DMA window, " "error %i (%s)\n", errno, strerror(errno)); return -1; } /* create DMA window from 0 to max(phys_addr + len) */ for (i = 0; i < RTE_MAX_MEMSEG; i++) { if (ms[i].addr == NULL) break; create.window_size = RTE_MAX(create.window_size, ms[i].iova + ms[i].len); } /* sPAPR requires window size to be a power of 2 */ create.window_size = rte_align64pow2(create.window_size); create.page_shift = __builtin_ctzll(ms->hugepage_sz); create.levels = 1; ret = ioctl(vfio_container_fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create); if (ret) { RTE_LOG(ERR, EAL, " cannot create new DMA window, " "error %i (%s)\n", errno, strerror(errno)); return -1; } if (create.start_addr != 0) { RTE_LOG(ERR, EAL, " DMA window start address != 0\n"); return -1; } /* map all DPDK segments for DMA. use 1:1 PA to IOVA mapping */ for (i = 0; i < RTE_MAX_MEMSEG; i++) { struct vfio_iommu_type1_dma_map dma_map; if (ms[i].addr == NULL) break; reg.vaddr = (uintptr_t) ms[i].addr; reg.size = ms[i].len; ret = ioctl(vfio_container_fd, VFIO_IOMMU_SPAPR_REGISTER_MEMORY, ®); if (ret) { RTE_LOG(ERR, EAL, " cannot register vaddr for IOMMU, " "error %i (%s)\n", errno, strerror(errno)); return -1; } memset(&dma_map, 0, sizeof(dma_map)); dma_map.argsz = sizeof(struct vfio_iommu_type1_dma_map); dma_map.vaddr = ms[i].addr_64; dma_map.size = ms[i].len; dma_map.iova = ms[i].iova; dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE; ret = ioctl(vfio_container_fd, VFIO_IOMMU_MAP_DMA, &dma_map); if (ret) { RTE_LOG(ERR, EAL, " cannot set up DMA remapping, " "error %i (%s)\n", errno, strerror(errno)); return -1; } } return 0; } static int vfio_noiommu_dma_map(int __rte_unused vfio_container_fd) { /* No-IOMMU mode does not need DMA mapping */ return 0; } int rte_vfio_noiommu_is_enabled(void) { int fd, ret, cnt __rte_unused; char c; ret = -1; fd = open(VFIO_NOIOMMU_MODE, O_RDONLY); if (fd < 0) return -1; cnt = read(fd, &c, 1); if (c == 'Y') ret = 1; close(fd); return ret; }