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) \ 24static struct hyp_sysfs_attr _name##_attr = __ATTR_RO(_name) 25 26#define HYPERVISOR_ATTR_RW(_name) \ 27static struct hyp_sysfs_attr _name##_attr = \ 28 __ATTR(_name, 0644, _name##_show, _name##_store) 29 30struct 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 37static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer) 38{ 39 return sprintf(buffer, "xen\n"); 40} 41 42HYPERVISOR_ATTR_RO(type); 43 44static int __init xen_sysfs_type_init(void) 45{ 46 return sysfs_create_file(hypervisor_kobj, &type_attr.attr); 47} 48 49static void xen_sysfs_type_destroy(void) 50{ 51 sysfs_remove_file(hypervisor_kobj, &type_attr.attr); 52} 53 54/* xen version attributes */ 55static 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 63HYPERVISOR_ATTR_RO(major); 64 65static 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 73HYPERVISOR_ATTR_RO(minor); 74 75static 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 91HYPERVISOR_ATTR_RO(extra); 92 93static struct attribute *version_attrs[] = { 94 &major_attr.attr, 95 &minor_attr.attr, 96 &extra_attr.attr, 97 NULL 98}; 99 100static struct attribute_group version_group = { 101 .name = "version", 102 .attrs = version_attrs, 103}; 104 105static int __init xen_sysfs_version_init(void) 106{ 107 return sysfs_create_group(hypervisor_kobj, &version_group); 108} 109 110static void xen_sysfs_version_destroy(void) 111{ 112 sysfs_remove_group(hypervisor_kobj, &version_group); 113} 114 115/* UUID */ 116 117static 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 138HYPERVISOR_ATTR_RO(uuid); 139 140static int __init xen_sysfs_uuid_init(void) 141{ 142 return sysfs_create_file(hypervisor_kobj, &uuid_attr.attr); 143} 144 145static void xen_sysfs_uuid_destroy(void) 146{ 147 sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr); 148} 149 150/* xen compilation attributes */ 151 152static 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 168HYPERVISOR_ATTR_RO(compiler); 169 170static 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 186HYPERVISOR_ATTR_RO(compiled_by); 187 188static 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 204HYPERVISOR_ATTR_RO(compile_date); 205 206static struct attribute *xen_compile_attrs[] = { 207 &compiler_attr.attr, 208 &compiled_by_attr.attr, 209 &compile_date_attr.attr, 210 NULL 211}; 212 213static struct attribute_group xen_compilation_group = { 214 .name = "compilation", 215 .attrs = xen_compile_attrs, 216}; 217 218int __init static xen_compilation_init(void) 219{ 220 return sysfs_create_group(hypervisor_kobj, &xen_compilation_group); 221} 222 223static void xen_compilation_destroy(void) 224{ 225 sysfs_remove_group(hypervisor_kobj, &xen_compilation_group); 226} 227 228/* xen properties info */ 229 230static 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 246HYPERVISOR_ATTR_RO(capabilities); 247 248static 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 264HYPERVISOR_ATTR_RO(changeset); 265 266static 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 283HYPERVISOR_ATTR_RO(virtual_start); 284 285static 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 296HYPERVISOR_ATTR_RO(pagesize); 297 298static 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 311static 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 332HYPERVISOR_ATTR_RO(features); 333 334static 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 343static struct attribute_group xen_properties_group = { 344 .name = "properties", 345 .attrs = xen_properties_attrs, 346}; 347 348static int __init xen_properties_init(void) 349{ 350 return sysfs_create_group(hypervisor_kobj, &xen_properties_group); 351} 352 353static void xen_properties_destroy(void) 354{ 355 sysfs_remove_group(hypervisor_kobj, &xen_properties_group); 356} 357 358static 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 383prop_out: 384 xen_sysfs_uuid_destroy(); 385uuid_out: 386 xen_compilation_destroy(); 387comp_out: 388 xen_sysfs_version_destroy(); 389version_out: 390 xen_sysfs_type_destroy(); 391out: 392 return ret; 393} 394 395static 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} 404module_init(hyper_sysfs_init); 405module_exit(hyper_sysfs_exit); 406 407static 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 418static 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 430static const struct sysfs_ops hyp_sysfs_ops = { 431 .show = hyp_sysfs_show, 432 .store = hyp_sysfs_store, 433}; 434 435static struct kobj_type hyp_sysfs_kobj_type = { 436 .sysfs_ops = &hyp_sysfs_ops, 437}; 438 439static 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} 447device_initcall(hypervisor_subsys_init); 448