// SPDX-License-Identifier: GPL-2.0-only #include #include #include #include #include #include #define readlink_safe(_path, _buf) ({ \ int __ret; \ \ _Static_assert(!__builtin_types_compatible_p( \ __typeof__(_buf), char *), \ "readlink_safe: _buf must be an array, not a pointer"); \ \ __ret = readlink(_path, _buf, sizeof(_buf) - 1); \ if (__ret != -1) \ _buf[__ret] = 0; \ __ret; \ }) static void readlink_base(const char *path, const char *data_fmt, void *out_data) { char rl_path[PATH_MAX]; int ret; ret = readlink_safe(path, rl_path); VFIO_ASSERT_NE(ret, -1); ret = sscanf(basename(rl_path), data_fmt, out_data); VFIO_ASSERT_EQ(ret, 1); } static int sysfs_val_get_int(const char *component, const char *name, const char *file) { char path[PATH_MAX]; char buf[32]; int ret; int fd; snprintf_assert(path, PATH_MAX, "/sys/bus/pci/%s/%s/%s", component, name, file); fd = open(path, O_RDONLY); if (fd < 0) return fd; VFIO_ASSERT_GT(read(fd, buf, ARRAY_SIZE(buf)), 0); VFIO_ASSERT_EQ(close(fd), 0); errno = 0; ret = strtol(buf, NULL, 0); VFIO_ASSERT_EQ(errno, 0, "sysfs path \"%s\" is not an integer: \"%s\"\n", path, buf); return ret; } static void sysfs_val_set(const char *component, const char *name, const char *file, const char *val) { char path[PATH_MAX]; int fd; snprintf_assert(path, PATH_MAX, "/sys/bus/pci/%s/%s/%s", component, name, file); VFIO_ASSERT_GT(fd = open(path, O_WRONLY), 0); VFIO_ASSERT_EQ(write(fd, val, strlen(val)), strlen(val)); VFIO_ASSERT_EQ(close(fd), 0); } static int sysfs_device_val_get(const char *bdf, const char *file) { return sysfs_val_get_int("devices", bdf, file); } static void sysfs_device_val_set(const char *bdf, const char *file, const char *val) { sysfs_val_set("devices", bdf, file, val); } static void sysfs_device_val_set_int(const char *bdf, const char *file, int val) { char val_str[32]; snprintf_assert(val_str, sizeof(val_str), "%d", val); sysfs_device_val_set(bdf, file, val_str); } int sysfs_sriov_totalvfs_get(const char *bdf) { return sysfs_device_val_get(bdf, "sriov_totalvfs"); } int sysfs_sriov_numvfs_get(const char *bdf) { return sysfs_device_val_get(bdf, "sriov_numvfs"); } void sysfs_sriov_numvfs_set(const char *bdf, int numvfs) { sysfs_device_val_set_int(bdf, "sriov_numvfs", numvfs); } char *sysfs_sriov_vf_bdf_get(const char *pf_bdf, int i) { char path[PATH_MAX]; char *out_vf_bdf; /* Fit "0000:00:00.0" */ out_vf_bdf = calloc(16, sizeof(char)); VFIO_ASSERT_NOT_NULL(out_vf_bdf); snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/virtfn%d", pf_bdf, i); readlink_base(path, "%s", out_vf_bdf); return out_vf_bdf; } int sysfs_iommu_group_get(const char *bdf) { char path[PATH_MAX]; int group; snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/iommu_group", bdf); readlink_base(path, "%d", &group); return group; } char *sysfs_driver_get(const char *bdf) { char driver_path[PATH_MAX]; char path[PATH_MAX]; char *out_driver; int ret; snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/driver", bdf); ret = readlink_safe(path, driver_path); if (ret == -1) { if (errno == ENOENT) return NULL; VFIO_FAIL("Failed to read %s\n", path); } out_driver = strdup(basename(driver_path)); VFIO_ASSERT_NOT_NULL(out_driver); return out_driver; }