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