Loading Documentation/ABI/testing/sysfs-hypervisor-haven 0 → 100644 +32 −0 Original line number Diff line number Diff line What: /sys/hypervisor/type Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven: Type of hypervisor: "haven": Haven hypervisor What: /sys/hypervisor/version/api Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven: The Haven API version. What: /sys/hypervisor/version/variant Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven: The Haven variant (build) version. What: /sys/kernel/debug/haven/trace_set Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven with Trace Control support: When reading, gets active trace class flags as a hexadecimal. When writing, adds to the trace class flags. What: /sys/kernel/debug/haven/trace_clear Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven with Trace Control support: When reading, gets active trace class flags as a hexadecimal. When writing, clears the specified trace class flags. drivers/virt/haven/Kconfig +22 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ menuconfig HAVEN_DRIVERS bool "Haven Virtualization drivers" depends on ARM64 help The Haven drivers are the helper interfaces that runs on the virtual machines that provides support such as memory/device Loading @@ -14,6 +15,27 @@ menuconfig HAVEN_DRIVERS if HAVEN_DRIVERS config HH_CTRL tristate "Create Haven entries under /sys/hypervisor" depends on SYSFS select SYS_HYPERVISOR help Create entries under /sys/hypervisor for the Haven hypervisor. The driver also provides a facility for controlling hypervisor debug features. See Documentation/ABI/testing/sysfs-hypervisor-haven for more details. if HH_CTRL config HH_DISABLE_UART bool "Disable Haven UART print during kernel boot" default y help The hypervisor UART driver is enabled at boot, however its use may conflict with use of the Linux driver. This config requests Haven to disable its UART driver. endif config HH_MSGQ tristate "Haven Message Queue driver" help Loading drivers/virt/haven/Makefile +1 −0 Original line number Diff line number Diff line # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_HH_CTRL) += hh_ctrl.o obj-$(CONFIG_HH_MSGQ) += hh_msgq.o obj-$(CONFIG_HH_RM_DRV) += hh_rm_drv.o hh_rm_drv-y := hh_rm_core.o hh_rm_iface.o Loading drivers/virt/haven/hh_ctrl.c 0 → 100644 +213 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "haven: " #include <linux/arm-smccc.h> #include <linux/debugfs.h> #include <linux/module.h> #include <linux/kobject.h> #include <linux/of.h> #include <linux/printk.h> #include <linux/slab.h> #include <linux/haven/hcall.h> #include <linux/haven/hh_errno.h> #define QC_HYP_SMCCC_UART_DISABLE \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ ARM_SMCCC_OWNER_VENDOR_HYPERVISOR, 0x0) #define QC_HYP_SMCCC_CALL_UID \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ ARM_SMCCC_OWNER_VENDOR_HYPERVISOR, 0xff01) #define QC_HYP_SMCCC_REVISION \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ ARM_SMCCC_OWNER_VENDOR_HYPERVISOR, 0xff03) #define QC_HYP_UID0 0x19bd54bd #define QC_HYP_UID1 0x0b37571b #define QC_HYP_UID2 0x946f609b #define QC_HYP_UID3 0x54539de6 #define HH_API_INFO_API_VERSION(x) (((x) >> 0) & 0x3fff) #define HH_API_INFO_BIG_ENDIAN(x) (((x) >> 14) & 1) #define HH_API_INFO_IS_64BIT(x) (((x) >> 15) & 1) #define HH_API_INFO_VARIANT(x) (((x) >> 56) & 0xff) #define HH_IDENTIFY_PARTITION_CSPACE(x) (((x) >> 0) & 1) #define HH_IDENTIFY_DOORBELL(x) (((x) >> 1) & 1) #define HH_IDENTIFY_MSGQUEUE(x) (((x) >> 2) & 1) #define HH_IDENTIFY_VIC(x) (((x) >> 3) & 1) #define HH_IDENTIFY_VPM(x) (((x) >> 4) & 1) #define HH_IDENTIFY_VCPU(x) (((x) >> 5) & 1) #define HH_IDENTIFY_MEMEXTENT(x) (((x) >> 6) & 1) #define HH_IDENTIFY_TRACE_CTRL(x) (((x) >> 7) & 1) #define HH_IDENTIFY_ROOTVM_CHANNEL(x) (((x) >> 16) & 1) #define HH_IDENTIFY_SCHEDULER(x) (((x) >> 28) & 0xf) static bool qc_hyp_calls; static struct hh_hcall_hyp_identify_resp haven_api; #if defined(CONFIG_HH_DISABLE_UART) static void hh_disable_uart(void) { if (qc_hyp_calls) arm_smccc_1_1_smc(QC_HYP_SMCCC_UART_DISABLE, NULL); } #endif static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buffer) { return scnprintf(buffer, PAGE_SIZE, "haven\n"); } static struct kobj_attribute type_attr = __ATTR_RO(type); static ssize_t api_show(struct kobject *kobj, struct kobj_attribute *attr, char *buffer) { return scnprintf(buffer, PAGE_SIZE, "%d\n", (int)HH_API_INFO_API_VERSION(haven_api.api_info)); } static struct kobj_attribute api_attr = __ATTR_RO(api); static ssize_t variant_show(struct kobject *kobj, struct kobj_attribute *attr, char *buffer) { return scnprintf(buffer, PAGE_SIZE, "%d\n", (int)HH_API_INFO_VARIANT(haven_api.api_info)); } static struct kobj_attribute variant_attr = __ATTR_RO(variant); static struct attribute *version_attrs[] = { &api_attr.attr, &variant_attr.attr, NULL }; static const struct attribute_group version_group = { .name = "version", .attrs = version_attrs, }; static int __init hh_sysfs_register(void) { int ret; ret = sysfs_create_file(hypervisor_kobj, &type_attr.attr); if (ret) return ret; return sysfs_create_group(hypervisor_kobj, &version_group); } static void __exit hh_sysfs_unregister(void) { sysfs_remove_file(hypervisor_kobj, &type_attr.attr); sysfs_remove_group(hypervisor_kobj, &version_group); } #if defined(CONFIG_DEBUG_FS) static struct dentry *hh_dbgfs_dir; static int hh_dbgfs_trace_class_set(void *data, u64 val) { return hh_remap_error(hh_hcall_trace_update_class_flags(val, 0, NULL)); } static int hh_dbgfs_trace_class_clear(void *data, u64 val) { return hh_remap_error(hh_hcall_trace_update_class_flags(0, val, NULL)); } static int hh_dbgfs_trace_class_get(void *data, u64 *val) { return hh_remap_error(hh_hcall_trace_update_class_flags(0, 0, val)); } DEFINE_DEBUGFS_ATTRIBUTE(hh_dbgfs_trace_class_set_fops, hh_dbgfs_trace_class_get, hh_dbgfs_trace_class_set, "0x%llx\n"); DEFINE_DEBUGFS_ATTRIBUTE(hh_dbgfs_trace_class_clear_fops, hh_dbgfs_trace_class_get, hh_dbgfs_trace_class_clear, "0x%llx\n"); static int __init hh_dbgfs_register(void) { struct dentry *dentry; hh_dbgfs_dir = debugfs_create_dir("haven", NULL); if (IS_ERR_OR_NULL(hh_dbgfs_dir)) return PTR_ERR(hh_dbgfs_dir); if (HH_IDENTIFY_TRACE_CTRL(haven_api.flags[0])) { dentry = debugfs_create_file("trace_set", 0600, hh_dbgfs_dir, NULL, &hh_dbgfs_trace_class_set_fops); if (IS_ERR(dentry)) return PTR_ERR(dentry); dentry = debugfs_create_file("trace_clear", 0600, hh_dbgfs_dir, NULL, &hh_dbgfs_trace_class_clear_fops); if (IS_ERR(dentry)) return PTR_ERR(dentry); } return 0; } static void __exit hh_dbgfs_unregister(void) { debugfs_remove_recursive(hh_dbgfs_dir); } #else /* !defined (CONFIG_DEBUG_FS) */ static inline int hh_dbgfs_register(void) { return 0; } static inline void hh_dbgfs_unregister(void) { return 0; } #endif static int __init hh_ctrl_init(void) { int ret; struct device_node *hyp; struct arm_smccc_res res; hyp = of_find_node_by_path("/hypervisor"); if (!hyp || !of_device_is_compatible(hyp, "qcom,haven-hypervisor")) return -ENODEV; (void)hh_hcall_hyp_identify(&haven_api); if (HH_API_INFO_API_VERSION(haven_api.api_info) != 1) { pr_err("unknown version\n"); return -ENODEV; } /* Check for ARM SMCCC VENDOR_HYP service calls by UID. */ arm_smccc_1_1_smc(QC_HYP_SMCCC_CALL_UID, &res); if ((res.a0 == QC_HYP_UID0) && (res.a1 == QC_HYP_UID1) && (res.a2 == QC_HYP_UID2) && (res.a3 == QC_HYP_UID3)) qc_hyp_calls = true; #if defined(CONFIG_HH_DISABLE_UART) hh_disable_uart(); #endif ret = hh_sysfs_register(); if (ret) return ret; ret = hh_dbgfs_register(); if (ret) pr_warn("failed to register dbgfs: %d\n", ret); return 0; } module_init(hh_ctrl_init); static void __exit hh_ctrl_exit(void) { hh_sysfs_unregister(); hh_dbgfs_unregister(); } module_exit(hh_ctrl_exit); include/linux/arm-smccc.h +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ #define ARM_SMCCC_OWNER_SIP 2 #define ARM_SMCCC_OWNER_OEM 3 #define ARM_SMCCC_OWNER_STANDARD 4 #define ARM_SMCCC_OWNER_STANDARD_HYPERVISOR 5 #define ARM_SMCCC_OWNER_VENDOR_HYPERVISOR 6 #define ARM_SMCCC_OWNER_TRUSTED_APP 48 #define ARM_SMCCC_OWNER_TRUSTED_APP_END 49 #define ARM_SMCCC_OWNER_TRUSTED_OS 50 Loading Loading
Documentation/ABI/testing/sysfs-hypervisor-haven 0 → 100644 +32 −0 Original line number Diff line number Diff line What: /sys/hypervisor/type Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven: Type of hypervisor: "haven": Haven hypervisor What: /sys/hypervisor/version/api Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven: The Haven API version. What: /sys/hypervisor/version/variant Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven: The Haven variant (build) version. What: /sys/kernel/debug/haven/trace_set Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven with Trace Control support: When reading, gets active trace class flags as a hexadecimal. When writing, adds to the trace class flags. What: /sys/kernel/debug/haven/trace_clear Date: April 2020 KernelVersion: 5.4.25 Description: If running under Haven with Trace Control support: When reading, gets active trace class flags as a hexadecimal. When writing, clears the specified trace class flags.
drivers/virt/haven/Kconfig +22 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ menuconfig HAVEN_DRIVERS bool "Haven Virtualization drivers" depends on ARM64 help The Haven drivers are the helper interfaces that runs on the virtual machines that provides support such as memory/device Loading @@ -14,6 +15,27 @@ menuconfig HAVEN_DRIVERS if HAVEN_DRIVERS config HH_CTRL tristate "Create Haven entries under /sys/hypervisor" depends on SYSFS select SYS_HYPERVISOR help Create entries under /sys/hypervisor for the Haven hypervisor. The driver also provides a facility for controlling hypervisor debug features. See Documentation/ABI/testing/sysfs-hypervisor-haven for more details. if HH_CTRL config HH_DISABLE_UART bool "Disable Haven UART print during kernel boot" default y help The hypervisor UART driver is enabled at boot, however its use may conflict with use of the Linux driver. This config requests Haven to disable its UART driver. endif config HH_MSGQ tristate "Haven Message Queue driver" help Loading
drivers/virt/haven/Makefile +1 −0 Original line number Diff line number Diff line # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_HH_CTRL) += hh_ctrl.o obj-$(CONFIG_HH_MSGQ) += hh_msgq.o obj-$(CONFIG_HH_RM_DRV) += hh_rm_drv.o hh_rm_drv-y := hh_rm_core.o hh_rm_iface.o Loading
drivers/virt/haven/hh_ctrl.c 0 → 100644 +213 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "haven: " #include <linux/arm-smccc.h> #include <linux/debugfs.h> #include <linux/module.h> #include <linux/kobject.h> #include <linux/of.h> #include <linux/printk.h> #include <linux/slab.h> #include <linux/haven/hcall.h> #include <linux/haven/hh_errno.h> #define QC_HYP_SMCCC_UART_DISABLE \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ ARM_SMCCC_OWNER_VENDOR_HYPERVISOR, 0x0) #define QC_HYP_SMCCC_CALL_UID \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ ARM_SMCCC_OWNER_VENDOR_HYPERVISOR, 0xff01) #define QC_HYP_SMCCC_REVISION \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ ARM_SMCCC_OWNER_VENDOR_HYPERVISOR, 0xff03) #define QC_HYP_UID0 0x19bd54bd #define QC_HYP_UID1 0x0b37571b #define QC_HYP_UID2 0x946f609b #define QC_HYP_UID3 0x54539de6 #define HH_API_INFO_API_VERSION(x) (((x) >> 0) & 0x3fff) #define HH_API_INFO_BIG_ENDIAN(x) (((x) >> 14) & 1) #define HH_API_INFO_IS_64BIT(x) (((x) >> 15) & 1) #define HH_API_INFO_VARIANT(x) (((x) >> 56) & 0xff) #define HH_IDENTIFY_PARTITION_CSPACE(x) (((x) >> 0) & 1) #define HH_IDENTIFY_DOORBELL(x) (((x) >> 1) & 1) #define HH_IDENTIFY_MSGQUEUE(x) (((x) >> 2) & 1) #define HH_IDENTIFY_VIC(x) (((x) >> 3) & 1) #define HH_IDENTIFY_VPM(x) (((x) >> 4) & 1) #define HH_IDENTIFY_VCPU(x) (((x) >> 5) & 1) #define HH_IDENTIFY_MEMEXTENT(x) (((x) >> 6) & 1) #define HH_IDENTIFY_TRACE_CTRL(x) (((x) >> 7) & 1) #define HH_IDENTIFY_ROOTVM_CHANNEL(x) (((x) >> 16) & 1) #define HH_IDENTIFY_SCHEDULER(x) (((x) >> 28) & 0xf) static bool qc_hyp_calls; static struct hh_hcall_hyp_identify_resp haven_api; #if defined(CONFIG_HH_DISABLE_UART) static void hh_disable_uart(void) { if (qc_hyp_calls) arm_smccc_1_1_smc(QC_HYP_SMCCC_UART_DISABLE, NULL); } #endif static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buffer) { return scnprintf(buffer, PAGE_SIZE, "haven\n"); } static struct kobj_attribute type_attr = __ATTR_RO(type); static ssize_t api_show(struct kobject *kobj, struct kobj_attribute *attr, char *buffer) { return scnprintf(buffer, PAGE_SIZE, "%d\n", (int)HH_API_INFO_API_VERSION(haven_api.api_info)); } static struct kobj_attribute api_attr = __ATTR_RO(api); static ssize_t variant_show(struct kobject *kobj, struct kobj_attribute *attr, char *buffer) { return scnprintf(buffer, PAGE_SIZE, "%d\n", (int)HH_API_INFO_VARIANT(haven_api.api_info)); } static struct kobj_attribute variant_attr = __ATTR_RO(variant); static struct attribute *version_attrs[] = { &api_attr.attr, &variant_attr.attr, NULL }; static const struct attribute_group version_group = { .name = "version", .attrs = version_attrs, }; static int __init hh_sysfs_register(void) { int ret; ret = sysfs_create_file(hypervisor_kobj, &type_attr.attr); if (ret) return ret; return sysfs_create_group(hypervisor_kobj, &version_group); } static void __exit hh_sysfs_unregister(void) { sysfs_remove_file(hypervisor_kobj, &type_attr.attr); sysfs_remove_group(hypervisor_kobj, &version_group); } #if defined(CONFIG_DEBUG_FS) static struct dentry *hh_dbgfs_dir; static int hh_dbgfs_trace_class_set(void *data, u64 val) { return hh_remap_error(hh_hcall_trace_update_class_flags(val, 0, NULL)); } static int hh_dbgfs_trace_class_clear(void *data, u64 val) { return hh_remap_error(hh_hcall_trace_update_class_flags(0, val, NULL)); } static int hh_dbgfs_trace_class_get(void *data, u64 *val) { return hh_remap_error(hh_hcall_trace_update_class_flags(0, 0, val)); } DEFINE_DEBUGFS_ATTRIBUTE(hh_dbgfs_trace_class_set_fops, hh_dbgfs_trace_class_get, hh_dbgfs_trace_class_set, "0x%llx\n"); DEFINE_DEBUGFS_ATTRIBUTE(hh_dbgfs_trace_class_clear_fops, hh_dbgfs_trace_class_get, hh_dbgfs_trace_class_clear, "0x%llx\n"); static int __init hh_dbgfs_register(void) { struct dentry *dentry; hh_dbgfs_dir = debugfs_create_dir("haven", NULL); if (IS_ERR_OR_NULL(hh_dbgfs_dir)) return PTR_ERR(hh_dbgfs_dir); if (HH_IDENTIFY_TRACE_CTRL(haven_api.flags[0])) { dentry = debugfs_create_file("trace_set", 0600, hh_dbgfs_dir, NULL, &hh_dbgfs_trace_class_set_fops); if (IS_ERR(dentry)) return PTR_ERR(dentry); dentry = debugfs_create_file("trace_clear", 0600, hh_dbgfs_dir, NULL, &hh_dbgfs_trace_class_clear_fops); if (IS_ERR(dentry)) return PTR_ERR(dentry); } return 0; } static void __exit hh_dbgfs_unregister(void) { debugfs_remove_recursive(hh_dbgfs_dir); } #else /* !defined (CONFIG_DEBUG_FS) */ static inline int hh_dbgfs_register(void) { return 0; } static inline void hh_dbgfs_unregister(void) { return 0; } #endif static int __init hh_ctrl_init(void) { int ret; struct device_node *hyp; struct arm_smccc_res res; hyp = of_find_node_by_path("/hypervisor"); if (!hyp || !of_device_is_compatible(hyp, "qcom,haven-hypervisor")) return -ENODEV; (void)hh_hcall_hyp_identify(&haven_api); if (HH_API_INFO_API_VERSION(haven_api.api_info) != 1) { pr_err("unknown version\n"); return -ENODEV; } /* Check for ARM SMCCC VENDOR_HYP service calls by UID. */ arm_smccc_1_1_smc(QC_HYP_SMCCC_CALL_UID, &res); if ((res.a0 == QC_HYP_UID0) && (res.a1 == QC_HYP_UID1) && (res.a2 == QC_HYP_UID2) && (res.a3 == QC_HYP_UID3)) qc_hyp_calls = true; #if defined(CONFIG_HH_DISABLE_UART) hh_disable_uart(); #endif ret = hh_sysfs_register(); if (ret) return ret; ret = hh_dbgfs_register(); if (ret) pr_warn("failed to register dbgfs: %d\n", ret); return 0; } module_init(hh_ctrl_init); static void __exit hh_ctrl_exit(void) { hh_sysfs_unregister(); hh_dbgfs_unregister(); } module_exit(hh_ctrl_exit);
include/linux/arm-smccc.h +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ #define ARM_SMCCC_OWNER_SIP 2 #define ARM_SMCCC_OWNER_OEM 3 #define ARM_SMCCC_OWNER_STANDARD 4 #define ARM_SMCCC_OWNER_STANDARD_HYPERVISOR 5 #define ARM_SMCCC_OWNER_VENDOR_HYPERVISOR 6 #define ARM_SMCCC_OWNER_TRUSTED_APP 48 #define ARM_SMCCC_OWNER_TRUSTED_APP_END 49 #define ARM_SMCCC_OWNER_TRUSTED_OS 50 Loading