sys-hypervisor.c 11 KB

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