linux/drivers/xen/sys-hypervisor.c
<<
>>
Prefs
   1/*
   2 *  copyright (c) 2006 IBM Corporation
   3 *  Authored by: Mike D. Day <ncmike@us.ibm.com>
   4 *
   5 *  This program is free software; you can redistribute it and/or modify
   6 *  it under the terms of the GNU General Public License version 2 as
   7 *  published by the Free Software Foundation.
   8 */
   9
  10#include <linux/slab.h>
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/kobject.h>
  14#include <linux/err.h>
  15
  16#include <asm/xen/hypervisor.h>
  17#include <asm/xen/hypercall.h>
  18
  19#include <xen/xen.h>
  20#include <xen/xenbus.h>
  21#include <xen/interface/xen.h>
  22#include <xen/interface/version.h>
  23
  24#define HYPERVISOR_ATTR_RO(_name) \
  25static struct hyp_sysfs_attr  _name##_attr = __ATTR_RO(_name)
  26
  27#define HYPERVISOR_ATTR_RW(_name) \
  28static struct hyp_sysfs_attr _name##_attr = \
  29        __ATTR(_name, 0644, _name##_show, _name##_store)
  30
  31struct hyp_sysfs_attr {
  32        struct attribute attr;
  33        ssize_t (*show)(struct hyp_sysfs_attr *, char *);
  34        ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t);
  35        void *hyp_attr_data;
  36};
  37
  38static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer)
  39{
  40        return sprintf(buffer, "xen\n");
  41}
  42
  43HYPERVISOR_ATTR_RO(type);
  44
  45static int __init xen_sysfs_type_init(void)
  46{
  47        return sysfs_create_file(hypervisor_kobj, &type_attr.attr);
  48}
  49
  50static void xen_sysfs_type_destroy(void)
  51{
  52        sysfs_remove_file(hypervisor_kobj, &type_attr.attr);
  53}
  54
  55/* xen version attributes */
  56static ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer)
  57{
  58        int version = HYPERVISOR_xen_version(XENVER_version, NULL);
  59        if (version)
  60                return sprintf(buffer, "%d\n", version >> 16);
  61        return -ENODEV;
  62}
  63
  64HYPERVISOR_ATTR_RO(major);
  65
  66static ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer)
  67{
  68        int version = HYPERVISOR_xen_version(XENVER_version, NULL);
  69        if (version)
  70                return sprintf(buffer, "%d\n", version & 0xff);
  71        return -ENODEV;
  72}
  73
  74HYPERVISOR_ATTR_RO(minor);
  75
  76static ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer)
  77{
  78        int ret = -ENOMEM;
  79        char *extra;
  80
  81        extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL);
  82        if (extra) {
  83                ret = HYPERVISOR_xen_version(XENVER_extraversion, extra);
  84                if (!ret)
  85                        ret = sprintf(buffer, "%s\n", extra);
  86                kfree(extra);
  87        }
  88
  89        return ret;
  90}
  91
  92HYPERVISOR_ATTR_RO(extra);
  93
  94static struct attribute *version_attrs[] = {
  95        &major_attr.attr,
  96        &minor_attr.attr,
  97        &extra_attr.attr,
  98        NULL
  99};
 100
 101static const struct attribute_group version_group = {
 102        .name = "version",
 103        .attrs = version_attrs,
 104};
 105
 106static int __init xen_sysfs_version_init(void)
 107{
 108        return sysfs_create_group(hypervisor_kobj, &version_group);
 109}
 110
 111static void xen_sysfs_version_destroy(void)
 112{
 113        sysfs_remove_group(hypervisor_kobj, &version_group);
 114}
 115
 116/* UUID */
 117
 118static ssize_t uuid_show_fallback(struct hyp_sysfs_attr *attr, char *buffer)
 119{
 120        char *vm, *val;
 121        int ret;
 122        extern int xenstored_ready;
 123
 124        if (!xenstored_ready)
 125                return -EBUSY;
 126
 127        vm = xenbus_read(XBT_NIL, "vm", "", NULL);
 128        if (IS_ERR(vm))
 129                return PTR_ERR(vm);
 130        val = xenbus_read(XBT_NIL, vm, "uuid", NULL);
 131        kfree(vm);
 132        if (IS_ERR(val))
 133                return PTR_ERR(val);
 134        ret = sprintf(buffer, "%s\n", val);
 135        kfree(val);
 136        return ret;
 137}
 138
 139static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
 140{
 141        xen_domain_handle_t uuid;
 142        int ret;
 143        ret = HYPERVISOR_xen_version(XENVER_guest_handle, uuid);
 144        if (ret)
 145                return uuid_show_fallback(attr, buffer);
 146        ret = sprintf(buffer, "%pU\n", uuid);
 147        return ret;
 148}
 149
 150HYPERVISOR_ATTR_RO(uuid);
 151
 152static int __init xen_sysfs_uuid_init(void)
 153{
 154        return sysfs_create_file(hypervisor_kobj, &uuid_attr.attr);
 155}
 156
 157static void xen_sysfs_uuid_destroy(void)
 158{
 159        sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr);
 160}
 161
 162/* xen compilation attributes */
 163
 164static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer)
 165{
 166        int ret = -ENOMEM;
 167        struct xen_compile_info *info;
 168
 169        info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
 170        if (info) {
 171                ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
 172                if (!ret)
 173                        ret = sprintf(buffer, "%s\n", info->compiler);
 174                kfree(info);
 175        }
 176
 177        return ret;
 178}
 179
 180HYPERVISOR_ATTR_RO(compiler);
 181
 182static ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer)
 183{
 184        int ret = -ENOMEM;
 185        struct xen_compile_info *info;
 186
 187        info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
 188        if (info) {
 189                ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
 190                if (!ret)
 191                        ret = sprintf(buffer, "%s\n", info->compile_by);
 192                kfree(info);
 193        }
 194
 195        return ret;
 196}
 197
 198HYPERVISOR_ATTR_RO(compiled_by);
 199
 200static ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer)
 201{
 202        int ret = -ENOMEM;
 203        struct xen_compile_info *info;
 204
 205        info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
 206        if (info) {
 207                ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
 208                if (!ret)
 209                        ret = sprintf(buffer, "%s\n", info->compile_date);
 210                kfree(info);
 211        }
 212
 213        return ret;
 214}
 215
 216HYPERVISOR_ATTR_RO(compile_date);
 217
 218static struct attribute *xen_compile_attrs[] = {
 219        &compiler_attr.attr,
 220        &compiled_by_attr.attr,
 221        &compile_date_attr.attr,
 222        NULL
 223};
 224
 225static const struct attribute_group xen_compilation_group = {
 226        .name = "compilation",
 227        .attrs = xen_compile_attrs,
 228};
 229
 230static int __init xen_compilation_init(void)
 231{
 232        return sysfs_create_group(hypervisor_kobj, &xen_compilation_group);
 233}
 234
 235static void xen_compilation_destroy(void)
 236{
 237        sysfs_remove_group(hypervisor_kobj, &xen_compilation_group);
 238}
 239
 240/* xen properties info */
 241
 242static ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer)
 243{
 244        int ret = -ENOMEM;
 245        char *caps;
 246
 247        caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL);
 248        if (caps) {
 249                ret = HYPERVISOR_xen_version(XENVER_capabilities, caps);
 250                if (!ret)
 251                        ret = sprintf(buffer, "%s\n", caps);
 252                kfree(caps);
 253        }
 254
 255        return ret;
 256}
 257
 258HYPERVISOR_ATTR_RO(capabilities);
 259
 260static ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer)
 261{
 262        int ret = -ENOMEM;
 263        char *cset;
 264
 265        cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL);
 266        if (cset) {
 267                ret = HYPERVISOR_xen_version(XENVER_changeset, cset);
 268                if (!ret)
 269                        ret = sprintf(buffer, "%s\n", cset);
 270                kfree(cset);
 271        }
 272
 273        return ret;
 274}
 275
 276HYPERVISOR_ATTR_RO(changeset);
 277
 278static ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer)
 279{
 280        int ret = -ENOMEM;
 281        struct xen_platform_parameters *parms;
 282
 283        parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL);
 284        if (parms) {
 285                ret = HYPERVISOR_xen_version(XENVER_platform_parameters,
 286                                             parms);
 287                if (!ret)
 288                        ret = sprintf(buffer, "%"PRI_xen_ulong"\n",
 289                                      parms->virt_start);
 290                kfree(parms);
 291        }
 292
 293        return ret;
 294}
 295
 296HYPERVISOR_ATTR_RO(virtual_start);
 297
 298static ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer)
 299{
 300        int ret;
 301
 302        ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL);
 303        if (ret > 0)
 304                ret = sprintf(buffer, "%x\n", ret);
 305
 306        return ret;
 307}
 308
 309HYPERVISOR_ATTR_RO(pagesize);
 310
 311static ssize_t xen_feature_show(int index, char *buffer)
 312{
 313        ssize_t ret;
 314        struct xen_feature_info info;
 315
 316        info.submap_idx = index;
 317        ret = HYPERVISOR_xen_version(XENVER_get_features, &info);
 318        if (!ret)
 319                ret = sprintf(buffer, "%08x", info.submap);
 320
 321        return ret;
 322}
 323
 324static ssize_t features_show(struct hyp_sysfs_attr *attr, char *buffer)
 325{
 326        ssize_t len;
 327        int i;
 328
 329        len = 0;
 330        for (i = XENFEAT_NR_SUBMAPS-1; i >= 0; i--) {
 331                int ret = xen_feature_show(i, buffer + len);
 332                if (ret < 0) {
 333                        if (len == 0)
 334                                len = ret;
 335                        break;
 336                }
 337                len += ret;
 338        }
 339        if (len > 0)
 340                buffer[len++] = '\n';
 341
 342        return len;
 343}
 344
 345HYPERVISOR_ATTR_RO(features);
 346
 347static struct attribute *xen_properties_attrs[] = {
 348        &capabilities_attr.attr,
 349        &changeset_attr.attr,
 350        &virtual_start_attr.attr,
 351        &pagesize_attr.attr,
 352        &features_attr.attr,
 353        NULL
 354};
 355
 356static const struct attribute_group xen_properties_group = {
 357        .name = "properties",
 358        .attrs = xen_properties_attrs,
 359};
 360
 361static int __init xen_properties_init(void)
 362{
 363        return sysfs_create_group(hypervisor_kobj, &xen_properties_group);
 364}
 365
 366static void xen_properties_destroy(void)
 367{
 368        sysfs_remove_group(hypervisor_kobj, &xen_properties_group);
 369}
 370
 371static int __init hyper_sysfs_init(void)
 372{
 373        int ret;
 374
 375        if (!xen_domain())
 376                return -ENODEV;
 377
 378        ret = xen_sysfs_type_init();
 379        if (ret)
 380                goto out;
 381        ret = xen_sysfs_version_init();
 382        if (ret)
 383                goto version_out;
 384        ret = xen_compilation_init();
 385        if (ret)
 386                goto comp_out;
 387        ret = xen_sysfs_uuid_init();
 388        if (ret)
 389                goto uuid_out;
 390        ret = xen_properties_init();
 391        if (ret)
 392                goto prop_out;
 393
 394        goto out;
 395
 396prop_out:
 397        xen_sysfs_uuid_destroy();
 398uuid_out:
 399        xen_compilation_destroy();
 400comp_out:
 401        xen_sysfs_version_destroy();
 402version_out:
 403        xen_sysfs_type_destroy();
 404out:
 405        return ret;
 406}
 407
 408static void __exit hyper_sysfs_exit(void)
 409{
 410        xen_properties_destroy();
 411        xen_compilation_destroy();
 412        xen_sysfs_uuid_destroy();
 413        xen_sysfs_version_destroy();
 414        xen_sysfs_type_destroy();
 415
 416}
 417module_init(hyper_sysfs_init);
 418module_exit(hyper_sysfs_exit);
 419
 420static ssize_t hyp_sysfs_show(struct kobject *kobj,
 421                              struct attribute *attr,
 422                              char *buffer)
 423{
 424        struct hyp_sysfs_attr *hyp_attr;
 425        hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
 426        if (hyp_attr->show)
 427                return hyp_attr->show(hyp_attr, buffer);
 428        return 0;
 429}
 430
 431static ssize_t hyp_sysfs_store(struct kobject *kobj,
 432                               struct attribute *attr,
 433                               const char *buffer,
 434                               size_t len)
 435{
 436        struct hyp_sysfs_attr *hyp_attr;
 437        hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
 438        if (hyp_attr->store)
 439                return hyp_attr->store(hyp_attr, buffer, len);
 440        return 0;
 441}
 442
 443static const struct sysfs_ops hyp_sysfs_ops = {
 444        .show = hyp_sysfs_show,
 445        .store = hyp_sysfs_store,
 446};
 447
 448static struct kobj_type hyp_sysfs_kobj_type = {
 449        .sysfs_ops = &hyp_sysfs_ops,
 450};
 451
 452static int __init hypervisor_subsys_init(void)
 453{
 454        if (!xen_domain())
 455                return -ENODEV;
 456
 457        hypervisor_kobj->ktype = &hyp_sysfs_kobj_type;
 458        return 0;
 459}
 460device_initcall(hypervisor_subsys_init);
 461