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) \ 25 static struct hyp_sysfs_attr _name##_attr = __ATTR_RO(_name) 26 27 #define HYPERVISOR_ATTR_RW(_name) \ 28 static struct hyp_sysfs_attr _name##_attr = \ 29 __ATTR(_name, 0644, _name##_show, _name##_store) 30 31 struct 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 38 static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer) 39 { 40 return sprintf(buffer, "xen\n"); 41 } 42 43 HYPERVISOR_ATTR_RO(type); 44 45 static int __init xen_sysfs_type_init(void) 46 { 47 return sysfs_create_file(hypervisor_kobj, &type_attr.attr); 48 } 49 50 static void xen_sysfs_type_destroy(void) 51 { 52 sysfs_remove_file(hypervisor_kobj, &type_attr.attr); 53 } 54 55 /* xen version attributes */ 56 static 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 64 HYPERVISOR_ATTR_RO(major); 65 66 static 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 74 HYPERVISOR_ATTR_RO(minor); 75 76 static 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 92 HYPERVISOR_ATTR_RO(extra); 93 94 static struct attribute *version_attrs[] = { 95 &major_attr.attr, 96 &minor_attr.attr, 97 &extra_attr.attr, 98 NULL 99 }; 100 101 static const struct attribute_group version_group = { 102 .name = "version", 103 .attrs = version_attrs, 104 }; 105 106 static int __init xen_sysfs_version_init(void) 107 { 108 return sysfs_create_group(hypervisor_kobj, &version_group); 109 } 110 111 static void xen_sysfs_version_destroy(void) 112 { 113 sysfs_remove_group(hypervisor_kobj, &version_group); 114 } 115 116 /* UUID */ 117 118 static 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 139 static 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 150 HYPERVISOR_ATTR_RO(uuid); 151 152 static int __init xen_sysfs_uuid_init(void) 153 { 154 return sysfs_create_file(hypervisor_kobj, &uuid_attr.attr); 155 } 156 157 static void xen_sysfs_uuid_destroy(void) 158 { 159 sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr); 160 } 161 162 /* xen compilation attributes */ 163 164 static 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 180 HYPERVISOR_ATTR_RO(compiler); 181 182 static 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 198 HYPERVISOR_ATTR_RO(compiled_by); 199 200 static 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 216 HYPERVISOR_ATTR_RO(compile_date); 217 218 static struct attribute *xen_compile_attrs[] = { 219 &compiler_attr.attr, 220 &compiled_by_attr.attr, 221 &compile_date_attr.attr, 222 NULL 223 }; 224 225 static const struct attribute_group xen_compilation_group = { 226 .name = "compilation", 227 .attrs = xen_compile_attrs, 228 }; 229 230 static int __init xen_compilation_init(void) 231 { 232 return sysfs_create_group(hypervisor_kobj, &xen_compilation_group); 233 } 234 235 static void xen_compilation_destroy(void) 236 { 237 sysfs_remove_group(hypervisor_kobj, &xen_compilation_group); 238 } 239 240 /* xen properties info */ 241 242 static 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 258 HYPERVISOR_ATTR_RO(capabilities); 259 260 static 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 276 HYPERVISOR_ATTR_RO(changeset); 277 278 static 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 296 HYPERVISOR_ATTR_RO(virtual_start); 297 298 static 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 309 HYPERVISOR_ATTR_RO(pagesize); 310 311 static 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 324 static 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 345 HYPERVISOR_ATTR_RO(features); 346 347 static 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 356 static const struct attribute_group xen_properties_group = { 357 .name = "properties", 358 .attrs = xen_properties_attrs, 359 }; 360 361 static int __init xen_properties_init(void) 362 { 363 return sysfs_create_group(hypervisor_kobj, &xen_properties_group); 364 } 365 366 static void xen_properties_destroy(void) 367 { 368 sysfs_remove_group(hypervisor_kobj, &xen_properties_group); 369 } 370 371 static 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 396 prop_out: 397 xen_sysfs_uuid_destroy(); 398 uuid_out: 399 xen_compilation_destroy(); 400 comp_out: 401 xen_sysfs_version_destroy(); 402 version_out: 403 xen_sysfs_type_destroy(); 404 out: 405 return ret; 406 } 407 408 static 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 } 417 module_init(hyper_sysfs_init); 418 module_exit(hyper_sysfs_exit); 419 420 static 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 431 static 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 443 static const struct sysfs_ops hyp_sysfs_ops = { 444 .show = hyp_sysfs_show, 445 .store = hyp_sysfs_store, 446 }; 447 448 static struct kobj_type hyp_sysfs_kobj_type = { 449 .sysfs_ops = &hyp_sysfs_ops, 450 }; 451 452 static 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 } 460 device_initcall(hypervisor_subsys_init); 461