Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  copyright (c) 2006 IBM Corporation
0004  *  Authored by: Mike D. Day <ncmike@us.ibm.com>
0005  */
0006 
0007 #include <linux/slab.h>
0008 #include <linux/kernel.h>
0009 #include <linux/init.h>
0010 #include <linux/kobject.h>
0011 #include <linux/err.h>
0012 
0013 #include <asm/xen/hypervisor.h>
0014 #include <asm/xen/hypercall.h>
0015 
0016 #include <xen/xen.h>
0017 #include <xen/xenbus.h>
0018 #include <xen/interface/xen.h>
0019 #include <xen/interface/version.h>
0020 #ifdef CONFIG_XEN_HAVE_VPMU
0021 #include <xen/interface/xenpmu.h>
0022 #endif
0023 
0024 #define HYPERVISOR_ATTR_RO(_name) \
0025 static struct hyp_sysfs_attr _name##_attr = __ATTR_RO(_name)
0026 
0027 #define HYPERVISOR_ATTR_RW(_name) \
0028 static struct hyp_sysfs_attr _name##_attr = __ATTR_RW(_name)
0029 
0030 struct hyp_sysfs_attr {
0031     struct attribute attr;
0032     ssize_t (*show)(struct hyp_sysfs_attr *, char *);
0033     ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t);
0034     void *hyp_attr_data;
0035 };
0036 
0037 static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer)
0038 {
0039     return sprintf(buffer, "xen\n");
0040 }
0041 
0042 HYPERVISOR_ATTR_RO(type);
0043 
0044 static int __init xen_sysfs_type_init(void)
0045 {
0046     return sysfs_create_file(hypervisor_kobj, &type_attr.attr);
0047 }
0048 
0049 static ssize_t guest_type_show(struct hyp_sysfs_attr *attr, char *buffer)
0050 {
0051     const char *type;
0052 
0053     switch (xen_domain_type) {
0054     case XEN_NATIVE:
0055         /* ARM only. */
0056         type = "Xen";
0057         break;
0058     case XEN_PV_DOMAIN:
0059         type = "PV";
0060         break;
0061     case XEN_HVM_DOMAIN:
0062         type = xen_pvh_domain() ? "PVH" : "HVM";
0063         break;
0064     default:
0065         return -EINVAL;
0066     }
0067 
0068     return sprintf(buffer, "%s\n", type);
0069 }
0070 
0071 HYPERVISOR_ATTR_RO(guest_type);
0072 
0073 static int __init xen_sysfs_guest_type_init(void)
0074 {
0075     return sysfs_create_file(hypervisor_kobj, &guest_type_attr.attr);
0076 }
0077 
0078 /* xen version attributes */
0079 static ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer)
0080 {
0081     int version = HYPERVISOR_xen_version(XENVER_version, NULL);
0082     if (version)
0083         return sprintf(buffer, "%d\n", version >> 16);
0084     return -ENODEV;
0085 }
0086 
0087 HYPERVISOR_ATTR_RO(major);
0088 
0089 static ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer)
0090 {
0091     int version = HYPERVISOR_xen_version(XENVER_version, NULL);
0092     if (version)
0093         return sprintf(buffer, "%d\n", version & 0xff);
0094     return -ENODEV;
0095 }
0096 
0097 HYPERVISOR_ATTR_RO(minor);
0098 
0099 static ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer)
0100 {
0101     int ret = -ENOMEM;
0102     char *extra;
0103 
0104     extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL);
0105     if (extra) {
0106         ret = HYPERVISOR_xen_version(XENVER_extraversion, extra);
0107         if (!ret)
0108             ret = sprintf(buffer, "%s\n", extra);
0109         kfree(extra);
0110     }
0111 
0112     return ret;
0113 }
0114 
0115 HYPERVISOR_ATTR_RO(extra);
0116 
0117 static struct attribute *version_attrs[] = {
0118     &major_attr.attr,
0119     &minor_attr.attr,
0120     &extra_attr.attr,
0121     NULL
0122 };
0123 
0124 static const struct attribute_group version_group = {
0125     .name = "version",
0126     .attrs = version_attrs,
0127 };
0128 
0129 static int __init xen_sysfs_version_init(void)
0130 {
0131     return sysfs_create_group(hypervisor_kobj, &version_group);
0132 }
0133 
0134 /* UUID */
0135 
0136 static ssize_t uuid_show_fallback(struct hyp_sysfs_attr *attr, char *buffer)
0137 {
0138     char *vm, *val;
0139     int ret;
0140     extern int xenstored_ready;
0141 
0142     if (!xenstored_ready)
0143         return -EBUSY;
0144 
0145     vm = xenbus_read(XBT_NIL, "vm", "", NULL);
0146     if (IS_ERR(vm))
0147         return PTR_ERR(vm);
0148     val = xenbus_read(XBT_NIL, vm, "uuid", NULL);
0149     kfree(vm);
0150     if (IS_ERR(val))
0151         return PTR_ERR(val);
0152     ret = sprintf(buffer, "%s\n", val);
0153     kfree(val);
0154     return ret;
0155 }
0156 
0157 static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
0158 {
0159     xen_domain_handle_t uuid;
0160     int ret;
0161     ret = HYPERVISOR_xen_version(XENVER_guest_handle, uuid);
0162     if (ret)
0163         return uuid_show_fallback(attr, buffer);
0164     ret = sprintf(buffer, "%pU\n", uuid);
0165     return ret;
0166 }
0167 
0168 HYPERVISOR_ATTR_RO(uuid);
0169 
0170 static int __init xen_sysfs_uuid_init(void)
0171 {
0172     return sysfs_create_file(hypervisor_kobj, &uuid_attr.attr);
0173 }
0174 
0175 /* xen compilation attributes */
0176 
0177 static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer)
0178 {
0179     int ret = -ENOMEM;
0180     struct xen_compile_info *info;
0181 
0182     info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
0183     if (info) {
0184         ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
0185         if (!ret)
0186             ret = sprintf(buffer, "%s\n", info->compiler);
0187         kfree(info);
0188     }
0189 
0190     return ret;
0191 }
0192 
0193 HYPERVISOR_ATTR_RO(compiler);
0194 
0195 static ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer)
0196 {
0197     int ret = -ENOMEM;
0198     struct xen_compile_info *info;
0199 
0200     info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
0201     if (info) {
0202         ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
0203         if (!ret)
0204             ret = sprintf(buffer, "%s\n", info->compile_by);
0205         kfree(info);
0206     }
0207 
0208     return ret;
0209 }
0210 
0211 HYPERVISOR_ATTR_RO(compiled_by);
0212 
0213 static ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer)
0214 {
0215     int ret = -ENOMEM;
0216     struct xen_compile_info *info;
0217 
0218     info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
0219     if (info) {
0220         ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
0221         if (!ret)
0222             ret = sprintf(buffer, "%s\n", info->compile_date);
0223         kfree(info);
0224     }
0225 
0226     return ret;
0227 }
0228 
0229 HYPERVISOR_ATTR_RO(compile_date);
0230 
0231 static struct attribute *xen_compile_attrs[] = {
0232     &compiler_attr.attr,
0233     &compiled_by_attr.attr,
0234     &compile_date_attr.attr,
0235     NULL
0236 };
0237 
0238 static const struct attribute_group xen_compilation_group = {
0239     .name = "compilation",
0240     .attrs = xen_compile_attrs,
0241 };
0242 
0243 static int __init xen_sysfs_compilation_init(void)
0244 {
0245     return sysfs_create_group(hypervisor_kobj, &xen_compilation_group);
0246 }
0247 
0248 /* xen properties info */
0249 
0250 static ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer)
0251 {
0252     int ret = -ENOMEM;
0253     char *caps;
0254 
0255     caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL);
0256     if (caps) {
0257         ret = HYPERVISOR_xen_version(XENVER_capabilities, caps);
0258         if (!ret)
0259             ret = sprintf(buffer, "%s\n", caps);
0260         kfree(caps);
0261     }
0262 
0263     return ret;
0264 }
0265 
0266 HYPERVISOR_ATTR_RO(capabilities);
0267 
0268 static ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer)
0269 {
0270     int ret = -ENOMEM;
0271     char *cset;
0272 
0273     cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL);
0274     if (cset) {
0275         ret = HYPERVISOR_xen_version(XENVER_changeset, cset);
0276         if (!ret)
0277             ret = sprintf(buffer, "%s\n", cset);
0278         kfree(cset);
0279     }
0280 
0281     return ret;
0282 }
0283 
0284 HYPERVISOR_ATTR_RO(changeset);
0285 
0286 static ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer)
0287 {
0288     int ret = -ENOMEM;
0289     struct xen_platform_parameters *parms;
0290 
0291     parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL);
0292     if (parms) {
0293         ret = HYPERVISOR_xen_version(XENVER_platform_parameters,
0294                          parms);
0295         if (!ret)
0296             ret = sprintf(buffer, "%"PRI_xen_ulong"\n",
0297                       parms->virt_start);
0298         kfree(parms);
0299     }
0300 
0301     return ret;
0302 }
0303 
0304 HYPERVISOR_ATTR_RO(virtual_start);
0305 
0306 static ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer)
0307 {
0308     int ret;
0309 
0310     ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL);
0311     if (ret > 0)
0312         ret = sprintf(buffer, "%x\n", ret);
0313 
0314     return ret;
0315 }
0316 
0317 HYPERVISOR_ATTR_RO(pagesize);
0318 
0319 static ssize_t xen_feature_show(int index, char *buffer)
0320 {
0321     ssize_t ret;
0322     struct xen_feature_info info;
0323 
0324     info.submap_idx = index;
0325     ret = HYPERVISOR_xen_version(XENVER_get_features, &info);
0326     if (!ret)
0327         ret = sprintf(buffer, "%08x", info.submap);
0328 
0329     return ret;
0330 }
0331 
0332 static ssize_t features_show(struct hyp_sysfs_attr *attr, char *buffer)
0333 {
0334     ssize_t len;
0335     int i;
0336 
0337     len = 0;
0338     for (i = XENFEAT_NR_SUBMAPS-1; i >= 0; i--) {
0339         int ret = xen_feature_show(i, buffer + len);
0340         if (ret < 0) {
0341             if (len == 0)
0342                 len = ret;
0343             break;
0344         }
0345         len += ret;
0346     }
0347     if (len > 0)
0348         buffer[len++] = '\n';
0349 
0350     return len;
0351 }
0352 
0353 HYPERVISOR_ATTR_RO(features);
0354 
0355 static ssize_t buildid_show(struct hyp_sysfs_attr *attr, char *buffer)
0356 {
0357     ssize_t ret;
0358     struct xen_build_id *buildid;
0359 
0360     ret = HYPERVISOR_xen_version(XENVER_build_id, NULL);
0361     if (ret < 0) {
0362         if (ret == -EPERM)
0363             ret = sprintf(buffer, "<denied>");
0364         return ret;
0365     }
0366 
0367     buildid = kmalloc(sizeof(*buildid) + ret, GFP_KERNEL);
0368     if (!buildid)
0369         return -ENOMEM;
0370 
0371     buildid->len = ret;
0372     ret = HYPERVISOR_xen_version(XENVER_build_id, buildid);
0373     if (ret > 0)
0374         ret = sprintf(buffer, "%s", buildid->buf);
0375     kfree(buildid);
0376 
0377     return ret;
0378 }
0379 
0380 HYPERVISOR_ATTR_RO(buildid);
0381 
0382 static struct attribute *xen_properties_attrs[] = {
0383     &capabilities_attr.attr,
0384     &changeset_attr.attr,
0385     &virtual_start_attr.attr,
0386     &pagesize_attr.attr,
0387     &features_attr.attr,
0388     &buildid_attr.attr,
0389     NULL
0390 };
0391 
0392 static const struct attribute_group xen_properties_group = {
0393     .name = "properties",
0394     .attrs = xen_properties_attrs,
0395 };
0396 
0397 static int __init xen_sysfs_properties_init(void)
0398 {
0399     return sysfs_create_group(hypervisor_kobj, &xen_properties_group);
0400 }
0401 
0402 #ifdef CONFIG_XEN_HAVE_VPMU
0403 struct pmu_mode {
0404     const char *name;
0405     uint32_t mode;
0406 };
0407 
0408 static struct pmu_mode pmu_modes[] = {
0409     {"off", XENPMU_MODE_OFF},
0410     {"self", XENPMU_MODE_SELF},
0411     {"hv", XENPMU_MODE_HV},
0412     {"all", XENPMU_MODE_ALL}
0413 };
0414 
0415 static ssize_t pmu_mode_store(struct hyp_sysfs_attr *attr,
0416                   const char *buffer, size_t len)
0417 {
0418     int ret;
0419     struct xen_pmu_params xp;
0420     int i;
0421 
0422     for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) {
0423         if (strncmp(buffer, pmu_modes[i].name, len - 1) == 0) {
0424             xp.val = pmu_modes[i].mode;
0425             break;
0426         }
0427     }
0428 
0429     if (i == ARRAY_SIZE(pmu_modes))
0430         return -EINVAL;
0431 
0432     xp.version.maj = XENPMU_VER_MAJ;
0433     xp.version.min = XENPMU_VER_MIN;
0434     ret = HYPERVISOR_xenpmu_op(XENPMU_mode_set, &xp);
0435     if (ret)
0436         return ret;
0437 
0438     return len;
0439 }
0440 
0441 static ssize_t pmu_mode_show(struct hyp_sysfs_attr *attr, char *buffer)
0442 {
0443     int ret;
0444     struct xen_pmu_params xp;
0445     int i;
0446     uint32_t mode;
0447 
0448     xp.version.maj = XENPMU_VER_MAJ;
0449     xp.version.min = XENPMU_VER_MIN;
0450     ret = HYPERVISOR_xenpmu_op(XENPMU_mode_get, &xp);
0451     if (ret)
0452         return ret;
0453 
0454     mode = (uint32_t)xp.val;
0455     for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) {
0456         if (mode == pmu_modes[i].mode)
0457             return sprintf(buffer, "%s\n", pmu_modes[i].name);
0458     }
0459 
0460     return -EINVAL;
0461 }
0462 HYPERVISOR_ATTR_RW(pmu_mode);
0463 
0464 static ssize_t pmu_features_store(struct hyp_sysfs_attr *attr,
0465                   const char *buffer, size_t len)
0466 {
0467     int ret;
0468     uint32_t features;
0469     struct xen_pmu_params xp;
0470 
0471     ret = kstrtou32(buffer, 0, &features);
0472     if (ret)
0473         return ret;
0474 
0475     xp.val = features;
0476     xp.version.maj = XENPMU_VER_MAJ;
0477     xp.version.min = XENPMU_VER_MIN;
0478     ret = HYPERVISOR_xenpmu_op(XENPMU_feature_set, &xp);
0479     if (ret)
0480         return ret;
0481 
0482     return len;
0483 }
0484 
0485 static ssize_t pmu_features_show(struct hyp_sysfs_attr *attr, char *buffer)
0486 {
0487     int ret;
0488     struct xen_pmu_params xp;
0489 
0490     xp.version.maj = XENPMU_VER_MAJ;
0491     xp.version.min = XENPMU_VER_MIN;
0492     ret = HYPERVISOR_xenpmu_op(XENPMU_feature_get, &xp);
0493     if (ret)
0494         return ret;
0495 
0496     return sprintf(buffer, "0x%x\n", (uint32_t)xp.val);
0497 }
0498 HYPERVISOR_ATTR_RW(pmu_features);
0499 
0500 static struct attribute *xen_pmu_attrs[] = {
0501     &pmu_mode_attr.attr,
0502     &pmu_features_attr.attr,
0503     NULL
0504 };
0505 
0506 static const struct attribute_group xen_pmu_group = {
0507     .name = "pmu",
0508     .attrs = xen_pmu_attrs,
0509 };
0510 
0511 static int __init xen_sysfs_pmu_init(void)
0512 {
0513     return sysfs_create_group(hypervisor_kobj, &xen_pmu_group);
0514 }
0515 #endif
0516 
0517 static int __init hyper_sysfs_init(void)
0518 {
0519     int ret;
0520 
0521     if (!xen_domain())
0522         return -ENODEV;
0523 
0524     ret = xen_sysfs_type_init();
0525     if (ret)
0526         goto out;
0527     ret = xen_sysfs_guest_type_init();
0528     if (ret)
0529         goto guest_type_out;
0530     ret = xen_sysfs_version_init();
0531     if (ret)
0532         goto version_out;
0533     ret = xen_sysfs_compilation_init();
0534     if (ret)
0535         goto comp_out;
0536     ret = xen_sysfs_uuid_init();
0537     if (ret)
0538         goto uuid_out;
0539     ret = xen_sysfs_properties_init();
0540     if (ret)
0541         goto prop_out;
0542 #ifdef CONFIG_XEN_HAVE_VPMU
0543     if (xen_initial_domain()) {
0544         ret = xen_sysfs_pmu_init();
0545         if (ret) {
0546             sysfs_remove_group(hypervisor_kobj,
0547                        &xen_properties_group);
0548             goto prop_out;
0549         }
0550     }
0551 #endif
0552     goto out;
0553 
0554 prop_out:
0555     sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr);
0556 uuid_out:
0557     sysfs_remove_group(hypervisor_kobj, &xen_compilation_group);
0558 comp_out:
0559     sysfs_remove_group(hypervisor_kobj, &version_group);
0560 version_out:
0561     sysfs_remove_file(hypervisor_kobj, &guest_type_attr.attr);
0562 guest_type_out:
0563     sysfs_remove_file(hypervisor_kobj, &type_attr.attr);
0564 out:
0565     return ret;
0566 }
0567 device_initcall(hyper_sysfs_init);
0568 
0569 static ssize_t hyp_sysfs_show(struct kobject *kobj,
0570                   struct attribute *attr,
0571                   char *buffer)
0572 {
0573     struct hyp_sysfs_attr *hyp_attr;
0574     hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
0575     if (hyp_attr->show)
0576         return hyp_attr->show(hyp_attr, buffer);
0577     return 0;
0578 }
0579 
0580 static ssize_t hyp_sysfs_store(struct kobject *kobj,
0581                    struct attribute *attr,
0582                    const char *buffer,
0583                    size_t len)
0584 {
0585     struct hyp_sysfs_attr *hyp_attr;
0586     hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
0587     if (hyp_attr->store)
0588         return hyp_attr->store(hyp_attr, buffer, len);
0589     return 0;
0590 }
0591 
0592 static const struct sysfs_ops hyp_sysfs_ops = {
0593     .show = hyp_sysfs_show,
0594     .store = hyp_sysfs_store,
0595 };
0596 
0597 static struct kobj_type hyp_sysfs_kobj_type = {
0598     .sysfs_ops = &hyp_sysfs_ops,
0599 };
0600 
0601 static int __init hypervisor_subsys_init(void)
0602 {
0603     if (!xen_domain())
0604         return -ENODEV;
0605 
0606     hypervisor_kobj->ktype = &hyp_sysfs_kobj_type;
0607     return 0;
0608 }
0609 device_initcall(hypervisor_subsys_init);