18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * copyright (c) 2006 IBM Corporation 48c2ecf20Sopenharmony_ci * Authored by: Mike D. Day <ncmike@us.ibm.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/kobject.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <asm/xen/hypervisor.h> 148c2ecf20Sopenharmony_ci#include <asm/xen/hypercall.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <xen/xen.h> 178c2ecf20Sopenharmony_ci#include <xen/xenbus.h> 188c2ecf20Sopenharmony_ci#include <xen/interface/xen.h> 198c2ecf20Sopenharmony_ci#include <xen/interface/version.h> 208c2ecf20Sopenharmony_ci#ifdef CONFIG_XEN_HAVE_VPMU 218c2ecf20Sopenharmony_ci#include <xen/interface/xenpmu.h> 228c2ecf20Sopenharmony_ci#endif 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define HYPERVISOR_ATTR_RO(_name) \ 258c2ecf20Sopenharmony_cistatic struct hyp_sysfs_attr _name##_attr = __ATTR_RO(_name) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define HYPERVISOR_ATTR_RW(_name) \ 288c2ecf20Sopenharmony_cistatic struct hyp_sysfs_attr _name##_attr = \ 298c2ecf20Sopenharmony_ci __ATTR(_name, 0644, _name##_show, _name##_store) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct hyp_sysfs_attr { 328c2ecf20Sopenharmony_ci struct attribute attr; 338c2ecf20Sopenharmony_ci ssize_t (*show)(struct hyp_sysfs_attr *, char *); 348c2ecf20Sopenharmony_ci ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t); 358c2ecf20Sopenharmony_ci void *hyp_attr_data; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci return sprintf(buffer, "xen\n"); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(type); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int __init xen_sysfs_type_init(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return sysfs_create_file(hypervisor_kobj, &type_attr.attr); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic ssize_t guest_type_show(struct hyp_sysfs_attr *attr, char *buffer) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci const char *type; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci switch (xen_domain_type) { 558c2ecf20Sopenharmony_ci case XEN_NATIVE: 568c2ecf20Sopenharmony_ci /* ARM only. */ 578c2ecf20Sopenharmony_ci type = "Xen"; 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci case XEN_PV_DOMAIN: 608c2ecf20Sopenharmony_ci type = "PV"; 618c2ecf20Sopenharmony_ci break; 628c2ecf20Sopenharmony_ci case XEN_HVM_DOMAIN: 638c2ecf20Sopenharmony_ci type = xen_pvh_domain() ? "PVH" : "HVM"; 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci default: 668c2ecf20Sopenharmony_ci return -EINVAL; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return sprintf(buffer, "%s\n", type); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(guest_type); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int __init xen_sysfs_guest_type_init(void) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return sysfs_create_file(hypervisor_kobj, &guest_type_attr.attr); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* xen version attributes */ 808c2ecf20Sopenharmony_cistatic ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci int version = HYPERVISOR_xen_version(XENVER_version, NULL); 838c2ecf20Sopenharmony_ci if (version) 848c2ecf20Sopenharmony_ci return sprintf(buffer, "%d\n", version >> 16); 858c2ecf20Sopenharmony_ci return -ENODEV; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(major); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci int version = HYPERVISOR_xen_version(XENVER_version, NULL); 938c2ecf20Sopenharmony_ci if (version) 948c2ecf20Sopenharmony_ci return sprintf(buffer, "%d\n", version & 0xff); 958c2ecf20Sopenharmony_ci return -ENODEV; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(minor); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int ret = -ENOMEM; 1038c2ecf20Sopenharmony_ci char *extra; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL); 1068c2ecf20Sopenharmony_ci if (extra) { 1078c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_extraversion, extra); 1088c2ecf20Sopenharmony_ci if (!ret) 1098c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%s\n", extra); 1108c2ecf20Sopenharmony_ci kfree(extra); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return ret; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(extra); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic struct attribute *version_attrs[] = { 1198c2ecf20Sopenharmony_ci &major_attr.attr, 1208c2ecf20Sopenharmony_ci &minor_attr.attr, 1218c2ecf20Sopenharmony_ci &extra_attr.attr, 1228c2ecf20Sopenharmony_ci NULL 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic const struct attribute_group version_group = { 1268c2ecf20Sopenharmony_ci .name = "version", 1278c2ecf20Sopenharmony_ci .attrs = version_attrs, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int __init xen_sysfs_version_init(void) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci return sysfs_create_group(hypervisor_kobj, &version_group); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* UUID */ 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic ssize_t uuid_show_fallback(struct hyp_sysfs_attr *attr, char *buffer) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci char *vm, *val; 1408c2ecf20Sopenharmony_ci int ret; 1418c2ecf20Sopenharmony_ci extern int xenstored_ready; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (!xenstored_ready) 1448c2ecf20Sopenharmony_ci return -EBUSY; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci vm = xenbus_read(XBT_NIL, "vm", "", NULL); 1478c2ecf20Sopenharmony_ci if (IS_ERR(vm)) 1488c2ecf20Sopenharmony_ci return PTR_ERR(vm); 1498c2ecf20Sopenharmony_ci val = xenbus_read(XBT_NIL, vm, "uuid", NULL); 1508c2ecf20Sopenharmony_ci kfree(vm); 1518c2ecf20Sopenharmony_ci if (IS_ERR(val)) 1528c2ecf20Sopenharmony_ci return PTR_ERR(val); 1538c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%s\n", val); 1548c2ecf20Sopenharmony_ci kfree(val); 1558c2ecf20Sopenharmony_ci return ret; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci xen_domain_handle_t uuid; 1618c2ecf20Sopenharmony_ci int ret; 1628c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_guest_handle, uuid); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci return uuid_show_fallback(attr, buffer); 1658c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%pU\n", uuid); 1668c2ecf20Sopenharmony_ci return ret; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(uuid); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int __init xen_sysfs_uuid_init(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci return sysfs_create_file(hypervisor_kobj, &uuid_attr.attr); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* xen compilation attributes */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci int ret = -ENOMEM; 1818c2ecf20Sopenharmony_ci struct xen_compile_info *info; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL); 1848c2ecf20Sopenharmony_ci if (info) { 1858c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_compile_info, info); 1868c2ecf20Sopenharmony_ci if (!ret) 1878c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%s\n", info->compiler); 1888c2ecf20Sopenharmony_ci kfree(info); 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return ret; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(compiler); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci int ret = -ENOMEM; 1998c2ecf20Sopenharmony_ci struct xen_compile_info *info; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL); 2028c2ecf20Sopenharmony_ci if (info) { 2038c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_compile_info, info); 2048c2ecf20Sopenharmony_ci if (!ret) 2058c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%s\n", info->compile_by); 2068c2ecf20Sopenharmony_ci kfree(info); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return ret; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(compiled_by); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci int ret = -ENOMEM; 2178c2ecf20Sopenharmony_ci struct xen_compile_info *info; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL); 2208c2ecf20Sopenharmony_ci if (info) { 2218c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_compile_info, info); 2228c2ecf20Sopenharmony_ci if (!ret) 2238c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%s\n", info->compile_date); 2248c2ecf20Sopenharmony_ci kfree(info); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(compile_date); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic struct attribute *xen_compile_attrs[] = { 2338c2ecf20Sopenharmony_ci &compiler_attr.attr, 2348c2ecf20Sopenharmony_ci &compiled_by_attr.attr, 2358c2ecf20Sopenharmony_ci &compile_date_attr.attr, 2368c2ecf20Sopenharmony_ci NULL 2378c2ecf20Sopenharmony_ci}; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic const struct attribute_group xen_compilation_group = { 2408c2ecf20Sopenharmony_ci .name = "compilation", 2418c2ecf20Sopenharmony_ci .attrs = xen_compile_attrs, 2428c2ecf20Sopenharmony_ci}; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int __init xen_sysfs_compilation_init(void) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci return sysfs_create_group(hypervisor_kobj, &xen_compilation_group); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* xen properties info */ 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci int ret = -ENOMEM; 2548c2ecf20Sopenharmony_ci char *caps; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL); 2578c2ecf20Sopenharmony_ci if (caps) { 2588c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_capabilities, caps); 2598c2ecf20Sopenharmony_ci if (!ret) 2608c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%s\n", caps); 2618c2ecf20Sopenharmony_ci kfree(caps); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return ret; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(capabilities); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci int ret = -ENOMEM; 2728c2ecf20Sopenharmony_ci char *cset; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL); 2758c2ecf20Sopenharmony_ci if (cset) { 2768c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_changeset, cset); 2778c2ecf20Sopenharmony_ci if (!ret) 2788c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%s\n", cset); 2798c2ecf20Sopenharmony_ci kfree(cset); 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return ret; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(changeset); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci int ret = -ENOMEM; 2908c2ecf20Sopenharmony_ci struct xen_platform_parameters *parms; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL); 2938c2ecf20Sopenharmony_ci if (parms) { 2948c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_platform_parameters, 2958c2ecf20Sopenharmony_ci parms); 2968c2ecf20Sopenharmony_ci if (!ret) 2978c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%"PRI_xen_ulong"\n", 2988c2ecf20Sopenharmony_ci parms->virt_start); 2998c2ecf20Sopenharmony_ci kfree(parms); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return ret; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(virtual_start); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int ret; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL); 3128c2ecf20Sopenharmony_ci if (ret > 0) 3138c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%x\n", ret); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return ret; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(pagesize); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic ssize_t xen_feature_show(int index, char *buffer) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci ssize_t ret; 3238c2ecf20Sopenharmony_ci struct xen_feature_info info; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci info.submap_idx = index; 3268c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_get_features, &info); 3278c2ecf20Sopenharmony_ci if (!ret) 3288c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%08x", info.submap); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic ssize_t features_show(struct hyp_sysfs_attr *attr, char *buffer) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci ssize_t len; 3368c2ecf20Sopenharmony_ci int i; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci len = 0; 3398c2ecf20Sopenharmony_ci for (i = XENFEAT_NR_SUBMAPS-1; i >= 0; i--) { 3408c2ecf20Sopenharmony_ci int ret = xen_feature_show(i, buffer + len); 3418c2ecf20Sopenharmony_ci if (ret < 0) { 3428c2ecf20Sopenharmony_ci if (len == 0) 3438c2ecf20Sopenharmony_ci len = ret; 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci len += ret; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci if (len > 0) 3498c2ecf20Sopenharmony_ci buffer[len++] = '\n'; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return len; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(features); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic ssize_t buildid_show(struct hyp_sysfs_attr *attr, char *buffer) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci ssize_t ret; 3598c2ecf20Sopenharmony_ci struct xen_build_id *buildid; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_build_id, NULL); 3628c2ecf20Sopenharmony_ci if (ret < 0) { 3638c2ecf20Sopenharmony_ci if (ret == -EPERM) 3648c2ecf20Sopenharmony_ci ret = sprintf(buffer, "<denied>"); 3658c2ecf20Sopenharmony_ci return ret; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci buildid = kmalloc(sizeof(*buildid) + ret, GFP_KERNEL); 3698c2ecf20Sopenharmony_ci if (!buildid) 3708c2ecf20Sopenharmony_ci return -ENOMEM; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci buildid->len = ret; 3738c2ecf20Sopenharmony_ci ret = HYPERVISOR_xen_version(XENVER_build_id, buildid); 3748c2ecf20Sopenharmony_ci if (ret > 0) 3758c2ecf20Sopenharmony_ci ret = sprintf(buffer, "%s", buildid->buf); 3768c2ecf20Sopenharmony_ci kfree(buildid); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return ret; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RO(buildid); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic struct attribute *xen_properties_attrs[] = { 3848c2ecf20Sopenharmony_ci &capabilities_attr.attr, 3858c2ecf20Sopenharmony_ci &changeset_attr.attr, 3868c2ecf20Sopenharmony_ci &virtual_start_attr.attr, 3878c2ecf20Sopenharmony_ci &pagesize_attr.attr, 3888c2ecf20Sopenharmony_ci &features_attr.attr, 3898c2ecf20Sopenharmony_ci &buildid_attr.attr, 3908c2ecf20Sopenharmony_ci NULL 3918c2ecf20Sopenharmony_ci}; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic const struct attribute_group xen_properties_group = { 3948c2ecf20Sopenharmony_ci .name = "properties", 3958c2ecf20Sopenharmony_ci .attrs = xen_properties_attrs, 3968c2ecf20Sopenharmony_ci}; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int __init xen_sysfs_properties_init(void) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci return sysfs_create_group(hypervisor_kobj, &xen_properties_group); 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci#ifdef CONFIG_XEN_HAVE_VPMU 4048c2ecf20Sopenharmony_cistruct pmu_mode { 4058c2ecf20Sopenharmony_ci const char *name; 4068c2ecf20Sopenharmony_ci uint32_t mode; 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic struct pmu_mode pmu_modes[] = { 4108c2ecf20Sopenharmony_ci {"off", XENPMU_MODE_OFF}, 4118c2ecf20Sopenharmony_ci {"self", XENPMU_MODE_SELF}, 4128c2ecf20Sopenharmony_ci {"hv", XENPMU_MODE_HV}, 4138c2ecf20Sopenharmony_ci {"all", XENPMU_MODE_ALL} 4148c2ecf20Sopenharmony_ci}; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic ssize_t pmu_mode_store(struct hyp_sysfs_attr *attr, 4178c2ecf20Sopenharmony_ci const char *buffer, size_t len) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci int ret; 4208c2ecf20Sopenharmony_ci struct xen_pmu_params xp; 4218c2ecf20Sopenharmony_ci int i; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) { 4248c2ecf20Sopenharmony_ci if (strncmp(buffer, pmu_modes[i].name, len - 1) == 0) { 4258c2ecf20Sopenharmony_ci xp.val = pmu_modes[i].mode; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(pmu_modes)) 4318c2ecf20Sopenharmony_ci return -EINVAL; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci xp.version.maj = XENPMU_VER_MAJ; 4348c2ecf20Sopenharmony_ci xp.version.min = XENPMU_VER_MIN; 4358c2ecf20Sopenharmony_ci ret = HYPERVISOR_xenpmu_op(XENPMU_mode_set, &xp); 4368c2ecf20Sopenharmony_ci if (ret) 4378c2ecf20Sopenharmony_ci return ret; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return len; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic ssize_t pmu_mode_show(struct hyp_sysfs_attr *attr, char *buffer) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci int ret; 4458c2ecf20Sopenharmony_ci struct xen_pmu_params xp; 4468c2ecf20Sopenharmony_ci int i; 4478c2ecf20Sopenharmony_ci uint32_t mode; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci xp.version.maj = XENPMU_VER_MAJ; 4508c2ecf20Sopenharmony_ci xp.version.min = XENPMU_VER_MIN; 4518c2ecf20Sopenharmony_ci ret = HYPERVISOR_xenpmu_op(XENPMU_mode_get, &xp); 4528c2ecf20Sopenharmony_ci if (ret) 4538c2ecf20Sopenharmony_ci return ret; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci mode = (uint32_t)xp.val; 4568c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) { 4578c2ecf20Sopenharmony_ci if (mode == pmu_modes[i].mode) 4588c2ecf20Sopenharmony_ci return sprintf(buffer, "%s\n", pmu_modes[i].name); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return -EINVAL; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RW(pmu_mode); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic ssize_t pmu_features_store(struct hyp_sysfs_attr *attr, 4668c2ecf20Sopenharmony_ci const char *buffer, size_t len) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci int ret; 4698c2ecf20Sopenharmony_ci uint32_t features; 4708c2ecf20Sopenharmony_ci struct xen_pmu_params xp; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci ret = kstrtou32(buffer, 0, &features); 4738c2ecf20Sopenharmony_ci if (ret) 4748c2ecf20Sopenharmony_ci return ret; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci xp.val = features; 4778c2ecf20Sopenharmony_ci xp.version.maj = XENPMU_VER_MAJ; 4788c2ecf20Sopenharmony_ci xp.version.min = XENPMU_VER_MIN; 4798c2ecf20Sopenharmony_ci ret = HYPERVISOR_xenpmu_op(XENPMU_feature_set, &xp); 4808c2ecf20Sopenharmony_ci if (ret) 4818c2ecf20Sopenharmony_ci return ret; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return len; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic ssize_t pmu_features_show(struct hyp_sysfs_attr *attr, char *buffer) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci int ret; 4898c2ecf20Sopenharmony_ci struct xen_pmu_params xp; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci xp.version.maj = XENPMU_VER_MAJ; 4928c2ecf20Sopenharmony_ci xp.version.min = XENPMU_VER_MIN; 4938c2ecf20Sopenharmony_ci ret = HYPERVISOR_xenpmu_op(XENPMU_feature_get, &xp); 4948c2ecf20Sopenharmony_ci if (ret) 4958c2ecf20Sopenharmony_ci return ret; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return sprintf(buffer, "0x%x\n", (uint32_t)xp.val); 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ciHYPERVISOR_ATTR_RW(pmu_features); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic struct attribute *xen_pmu_attrs[] = { 5028c2ecf20Sopenharmony_ci &pmu_mode_attr.attr, 5038c2ecf20Sopenharmony_ci &pmu_features_attr.attr, 5048c2ecf20Sopenharmony_ci NULL 5058c2ecf20Sopenharmony_ci}; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic const struct attribute_group xen_pmu_group = { 5088c2ecf20Sopenharmony_ci .name = "pmu", 5098c2ecf20Sopenharmony_ci .attrs = xen_pmu_attrs, 5108c2ecf20Sopenharmony_ci}; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int __init xen_sysfs_pmu_init(void) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci return sysfs_create_group(hypervisor_kobj, &xen_pmu_group); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci#endif 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int __init hyper_sysfs_init(void) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci int ret; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (!xen_domain()) 5238c2ecf20Sopenharmony_ci return -ENODEV; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci ret = xen_sysfs_type_init(); 5268c2ecf20Sopenharmony_ci if (ret) 5278c2ecf20Sopenharmony_ci goto out; 5288c2ecf20Sopenharmony_ci ret = xen_sysfs_guest_type_init(); 5298c2ecf20Sopenharmony_ci if (ret) 5308c2ecf20Sopenharmony_ci goto guest_type_out; 5318c2ecf20Sopenharmony_ci ret = xen_sysfs_version_init(); 5328c2ecf20Sopenharmony_ci if (ret) 5338c2ecf20Sopenharmony_ci goto version_out; 5348c2ecf20Sopenharmony_ci ret = xen_sysfs_compilation_init(); 5358c2ecf20Sopenharmony_ci if (ret) 5368c2ecf20Sopenharmony_ci goto comp_out; 5378c2ecf20Sopenharmony_ci ret = xen_sysfs_uuid_init(); 5388c2ecf20Sopenharmony_ci if (ret) 5398c2ecf20Sopenharmony_ci goto uuid_out; 5408c2ecf20Sopenharmony_ci ret = xen_sysfs_properties_init(); 5418c2ecf20Sopenharmony_ci if (ret) 5428c2ecf20Sopenharmony_ci goto prop_out; 5438c2ecf20Sopenharmony_ci#ifdef CONFIG_XEN_HAVE_VPMU 5448c2ecf20Sopenharmony_ci if (xen_initial_domain()) { 5458c2ecf20Sopenharmony_ci ret = xen_sysfs_pmu_init(); 5468c2ecf20Sopenharmony_ci if (ret) { 5478c2ecf20Sopenharmony_ci sysfs_remove_group(hypervisor_kobj, 5488c2ecf20Sopenharmony_ci &xen_properties_group); 5498c2ecf20Sopenharmony_ci goto prop_out; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci#endif 5538c2ecf20Sopenharmony_ci goto out; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ciprop_out: 5568c2ecf20Sopenharmony_ci sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr); 5578c2ecf20Sopenharmony_ciuuid_out: 5588c2ecf20Sopenharmony_ci sysfs_remove_group(hypervisor_kobj, &xen_compilation_group); 5598c2ecf20Sopenharmony_cicomp_out: 5608c2ecf20Sopenharmony_ci sysfs_remove_group(hypervisor_kobj, &version_group); 5618c2ecf20Sopenharmony_civersion_out: 5628c2ecf20Sopenharmony_ci sysfs_remove_file(hypervisor_kobj, &guest_type_attr.attr); 5638c2ecf20Sopenharmony_ciguest_type_out: 5648c2ecf20Sopenharmony_ci sysfs_remove_file(hypervisor_kobj, &type_attr.attr); 5658c2ecf20Sopenharmony_ciout: 5668c2ecf20Sopenharmony_ci return ret; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_cidevice_initcall(hyper_sysfs_init); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic ssize_t hyp_sysfs_show(struct kobject *kobj, 5718c2ecf20Sopenharmony_ci struct attribute *attr, 5728c2ecf20Sopenharmony_ci char *buffer) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct hyp_sysfs_attr *hyp_attr; 5758c2ecf20Sopenharmony_ci hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr); 5768c2ecf20Sopenharmony_ci if (hyp_attr->show) 5778c2ecf20Sopenharmony_ci return hyp_attr->show(hyp_attr, buffer); 5788c2ecf20Sopenharmony_ci return 0; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic ssize_t hyp_sysfs_store(struct kobject *kobj, 5828c2ecf20Sopenharmony_ci struct attribute *attr, 5838c2ecf20Sopenharmony_ci const char *buffer, 5848c2ecf20Sopenharmony_ci size_t len) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct hyp_sysfs_attr *hyp_attr; 5878c2ecf20Sopenharmony_ci hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr); 5888c2ecf20Sopenharmony_ci if (hyp_attr->store) 5898c2ecf20Sopenharmony_ci return hyp_attr->store(hyp_attr, buffer, len); 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic const struct sysfs_ops hyp_sysfs_ops = { 5948c2ecf20Sopenharmony_ci .show = hyp_sysfs_show, 5958c2ecf20Sopenharmony_ci .store = hyp_sysfs_store, 5968c2ecf20Sopenharmony_ci}; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic struct kobj_type hyp_sysfs_kobj_type = { 5998c2ecf20Sopenharmony_ci .sysfs_ops = &hyp_sysfs_ops, 6008c2ecf20Sopenharmony_ci}; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic int __init hypervisor_subsys_init(void) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci if (!xen_domain()) 6058c2ecf20Sopenharmony_ci return -ENODEV; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci hypervisor_kobj->ktype = &hyp_sysfs_kobj_type; 6088c2ecf20Sopenharmony_ci return 0; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_cidevice_initcall(hypervisor_subsys_init); 611