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