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