kvm: arm64: Disclose SPCI partition details in sysfs This allows user space to discover the preloaded partitions. Only information that a VMM needs is made available. Signed-off-by: Andrew Scull <ascull@google.com>
diff --git a/Documentation/ABI/testing/sysfs-hypervisor-spci b/Documentation/ABI/testing/sysfs-hypervisor-spci new file mode 100644 index 0000000..48f0b55 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-hypervisor-spci
@@ -0,0 +1,18 @@ +What: /sys/hypervisor/spci/partitionX/uuid +Date: April 2020 +KernelVersion: 5.8 +Contact: kvmarm@lists.cs.columbia.edu +Description: The UUID of the partition. + +What: /sys/hypervisor/spci/partitionX/vcpus +Date: April 2020 +KernelVersion: 5.8 +Contact: kvmarm@lists.cs.columbia.edu +Description: The number of vCPUs declared by the partition. + +What: /sys/hypervisor/spci/partitionX/exec_state +Date: April 2020 +KernelVersion: 5.8 +Contact: kvmarm@lists.cs.columbia.edu +Description: The execution state of the partition. + Currently "AArch32" or "AArch64".
diff --git a/MAINTAINERS b/MAINTAINERS index 7bff7e9..3130c32 100644 --- a/MAINTAINERS +++ b/MAINTAINERS
@@ -9295,6 +9295,7 @@ L: kvmarm@lists.cs.columbia.edu S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git +F: Documentation/ABI/testing/sysfs-hypervisor-spci F: arch/arm64/include/asm/kvm* F: arch/arm64/include/uapi/asm/kvm* F: arch/arm64/kvm/
diff --git a/arch/arm64/kvm/spci.c b/arch/arm64/kvm/spci.c index d73f956..b5225bd 100644 --- a/arch/arm64/kvm/spci.c +++ b/arch/arm64/kvm/spci.c
@@ -157,6 +157,60 @@ static int spci_parse_partition_entry_point(struct kvm_spci_partition *part, return 0; } +static struct kobj_type spci_part_ktype = { + .sysfs_ops = &kobj_sysfs_ops, +}; + +#define kobj_to_part(kobj) container_of(kobj, struct kvm_spci_partition, kobj) +#define SPCI_PART_ATTR_RO(_name, _fmt, ...) \ +static ssize_t _name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + char *buf) \ +{ \ + struct kvm_spci_partition *part = kobj_to_part(kobj); \ + \ + return sprintf(buf, _fmt, __VA_ARGS__); \ +} \ +static struct kobj_attribute spci_part_attr_##_name = __ATTR_RO(_name) + +SPCI_PART_ATTR_RO(uuid, "%pU\n", &part->uuid); +SPCI_PART_ATTR_RO(vcpus, "%d\n", part->nr_vcpus); +SPCI_PART_ATTR_RO(exec_state, "%s\n", part->is_32bit ? "AArch32" : "AArch64"); + +static struct attribute *spci_part_attrs[] = { + &spci_part_attr_uuid.attr, + &spci_part_attr_vcpus.attr, + &spci_part_attr_exec_state.attr, + NULL, +}; + +static const struct attribute_group spci_part_attr_group = { + .attrs = spci_part_attrs, +}; + +static struct kobject *spci_kobj; + +static int spci_partition_create_sysfs(struct kvm_spci_partition *part) +{ + int err; + + err = kobject_init_and_add(&part->kobj, &spci_part_ktype, spci_kobj, + "partition%d", part->id); + if (err) + goto out; + + err = sysfs_create_group(&part->kobj, &spci_part_attr_group); + if (err) + goto out_put_kobj; + + return 0; + +out_put_kobj: + kobject_put(&part->kobj); +out: + return err; +} + static int spci_parse_partitions(struct device_node *spci_np) { struct device_node *np, *prev_np = spci_np; @@ -223,6 +277,10 @@ static int spci_parse_partitions(struct device_node *spci_np) } part->id = nr_parts; + if (spci_partition_create_sysfs(part)) { + kvm_err("%s: failed to create sysfs entries\n", pfx); + goto next_free_part; + } ++nr_parts; INIT_LIST_HEAD(&part->list); @@ -307,8 +365,13 @@ static void spci_dump_partitions(void) int kvm_spci_init(void) { - int ret = spci_parse_dt_node(); + int ret; + spci_kobj = kobject_create_and_add("spci", hypervisor_kobj); + if (!spci_kobj) + return -ENOMEM; + + ret = spci_parse_dt_node(); if (ret) return ret;
diff --git a/include/kvm/arm_spci.h b/include/kvm/arm_spci.h index 54fd69b..71fde30 100644 --- a/include/kvm/arm_spci.h +++ b/include/kvm/arm_spci.h
@@ -8,6 +8,7 @@ #define __KVM_ARM_SPCI_H #include <linux/of_reserved_mem.h> +#include <linux/kobject.h> enum kvm_spci_mem_prot { KVM_SPCI_MEM_PROT_X = 1 << 0, @@ -23,6 +24,7 @@ struct kvm_spci_memory { }; struct kvm_spci_partition { + struct kobject kobj; struct list_head list; int id; uuid_t uuid;