Display various information about the Arm execution Facility (AEF) to userspace. The files are located in /sys/firmware/aef/. Show if the feature is available and usable for the host, which formats are available, and how many arm vCPUS per guest are supported by the machine. Additionally, provide the raw binary output of QAAF fc1 (Query Model Capabilities) in the file qmc and fc2 (Initial System-Registers-Save Area) in the file save_area. Co-developed-by: Janosch Frank Signed-off-by: Janosch Frank Co-developed-by: Andreas Grapentin Signed-off-by: Andreas Grapentin Signed-off-by: Steffen Eiden --- Documentation/ABI/testing/sysfs-firmware-aef | 70 +++++++++++++++++ arch/s390/kernel/aef.c | 113 +++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-firmware-aef b/Documentation/ABI/testing/sysfs-firmware-aef new file mode 100644 index 000000000000..6ccd8491a017 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-aef @@ -0,0 +1,70 @@ +What: /sys/firmware/aef/ +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Various interfaces to query information about the ARM + Execution Facility (AEF). + + The directory is present only on machines that provide + the AEF (SCLP facility bit). + +What: /sys/firmware/aef/arm_guest_supp +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Read-only, decimal boolean. Reports 1 if all requirements + for running arm64 KVM guests (KVM module kvm_arm64) are + satisfied by the machine, 0 otherwise. This is equivalent to the + logical AND of sae_avail, ptff_avail and edat2_avail below. + +What: /sys/firmware/aef/query/ +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Raw machine characteristics as reported by the QAAF + instruction. + +What: /sys/firmware/aef/query/sae_avail +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Read-only, decimal boolean. Reports 1 if the machine + provides the SAE instruction. + +What: /sys/firmware/aef/query/ptff_avail +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Read-only, decimal boolean. Reports 1 if the PTFF + instruction supports the QAGTO and QAGPT subfunctions. + +What: /sys/firmware/aef/query/edat2_avail +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Read-only, decimal boolean. Reports 1 if the EDAT-2 + facility is available. + +What: /sys/firmware/aef/query/supp_state_desc_formats +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Read-only, 0x-prefixed hexadecimal bitmask. Bitmask of + the SAE state description formats supported by the machine. + +What: /sys/firmware/aef/query/supp_save_area_formats +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Read-only, 0x-prefixed hexadecimal bitmask. Bitmask of + the SAE save area formats supported by the machine. + +What: /sys/firmware/aef/query/max_num_vcpu +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Read-only, decimal number. Maximum number of guest CPUs + per VM. + +What: /sys/firmware/aef/query/qmc +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Read-only binary attribute, 4096 bytes. Contains the + unmodified, machine specific QMC response block. + +What: /sys/firmware/aef/query/save_area +KernelVersion: 7.5 +Contact: linux-s390@vger.kernel.org +Description: Read-only binary attribute, 4096 bytes. Contains the + unmodified, machine specific GISRSA block. diff --git a/arch/s390/kernel/aef.c b/arch/s390/kernel/aef.c index 31e18953d7b3..96a6d63b2695 100644 --- a/arch/s390/kernel/aef.c +++ b/arch/s390/kernel/aef.c @@ -11,6 +11,15 @@ static struct qaaf_qmc_block qmc = {}; static struct kvm_sae_save_area save_area = {}; +static struct aef_info { + unsigned long arm_guest_supp; + unsigned long sae_avail; + unsigned long ptff_avail; + unsigned long edat2_avail; + unsigned long supp_state_desc_formats; + unsigned long supp_save_area_formats; + unsigned long max_num_vcpu; +} info = {}; const struct kvm_sae_save_area *aef_gisrsa(void) { @@ -38,6 +47,68 @@ bool aef_usable(void) } EXPORT_SYMBOL_GPL(aef_usable); +static struct kset *aef_query_kset; +static struct kobject *aef_kobj; + +#define aef_sysfs_qval_def(_name, _fmt) \ + static ssize_t _name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + char *buf) \ + { \ + return sysfs_emit(buf, _fmt "\n", info._name); \ + } \ + static struct kobj_attribute _name##_attr = __ATTR_RO(_name) + +#define aef_sysfs_qval_attr(_name) &_name##_attr.attr + +aef_sysfs_qval_def(arm_guest_supp, "%lu"); +aef_sysfs_qval_def(sae_avail, "%lu"); +aef_sysfs_qval_def(ptff_avail, "%lu"); +aef_sysfs_qval_def(edat2_avail, "%lu"); +aef_sysfs_qval_def(supp_state_desc_formats, "0x%lx"); +aef_sysfs_qval_def(supp_save_area_formats, "0x%lx"); +aef_sysfs_qval_def(max_num_vcpu, "%lu"); + +static ssize_t qmc_read(struct file *filp, struct kobject *kobj, + const struct bin_attribute *attr, char *buf, loff_t off, + size_t count) +{ + return memory_read_from_buffer(buf, count, &off, &qmc, sizeof(qmc)); +} + +BIN_ATTR_RO(qmc, sizeof(qmc)); + +static ssize_t save_area_read(struct file *filp, struct kobject *kobj, + const struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + return memory_read_from_buffer(buf, count, &off, &save_area, + sizeof(save_area)); +} + +BIN_ATTR_RO(save_area, sizeof(save_area)); + +static struct attribute *aef_query_attrs[] = { + aef_sysfs_qval_attr(sae_avail), + aef_sysfs_qval_attr(ptff_avail), + aef_sysfs_qval_attr(edat2_avail), + aef_sysfs_qval_attr(supp_state_desc_formats), + aef_sysfs_qval_attr(supp_save_area_formats), + aef_sysfs_qval_attr(max_num_vcpu), + NULL, +}; + +static const struct bin_attribute *aef_query_bin_attrs[] = { + &bin_attr_qmc, + &bin_attr_save_area, + NULL, +}; + +static struct attribute_group aef_query_attr_group = { + .attrs = aef_query_attrs, + .bin_attrs = aef_query_bin_attrs, +}; + static int __init aef_init_save_area(void) { int ret; @@ -71,6 +142,17 @@ static int __init aef_query_info(void) return 0; } +static void __init aef_info_init(void) +{ + info.sae_avail = sclp.has_aef; + info.ptff_avail = ptff_query(PTFF_QAGTO) && ptff_query(PTFF_QAGPT); + info.edat2_avail = cpu_has_edat2(); + info.arm_guest_supp = info.sae_avail && info.ptff_avail && info.edat2_avail; + info.supp_state_desc_formats = qmc.ssdf; + info.supp_save_area_formats = qmc.ssaf; + info.max_num_vcpu = qmc.maxncpu + 1; +} + static int __init aef_sysfs_init(void) { int rc; @@ -86,9 +168,40 @@ static int __init aef_sysfs_init(void) if (rc) return rc; + /* sysfs failure below does not invalidate the AEF data */ aef_valid = true; + aef_info_init(); + + aef_kobj = kobject_create_and_add("aef", firmware_kobj); + if (!aef_kobj) + return -ENOMEM; + + rc = sysfs_create_file(aef_kobj, aef_sysfs_qval_attr(arm_guest_supp)); + if (rc) + goto out_kobj; + + aef_query_kset = kset_create_and_add("query", NULL, aef_kobj); + if (!aef_query_kset) { + rc = -ENOMEM; + goto out_arm_guest_supp; + } + + rc = sysfs_create_group(&aef_query_kset->kobj, &aef_query_attr_group); + if (rc) + goto out_kset; + return 0; + +out_kset: + kset_unregister(aef_query_kset); +out_arm_guest_supp: + sysfs_remove_file(aef_kobj, &arm_guest_supp_attr.attr); +out_kobj: + kobject_del(aef_kobj); + kobject_put(aef_kobj); + + return rc; } arch_initcall(aef_sysfs_init); -- 2.56.0