0001
0002
0003
0004
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
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
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
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
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
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);