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