efi.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * EFI support for Xen.
  4. *
  5. * Copyright (C) 1999 VA Linux Systems
  6. * Copyright (C) 1999 Walt Drummond <[email protected]>
  7. * Copyright (C) 1999-2002 Hewlett-Packard Co.
  8. * David Mosberger-Tang <[email protected]>
  9. * Stephane Eranian <[email protected]>
  10. * Copyright (C) 2005-2008 Intel Co.
  11. * Fenghua Yu <[email protected]>
  12. * Bibo Mao <[email protected]>
  13. * Chandramouli Narayanan <[email protected]>
  14. * Huang Ying <[email protected]>
  15. * Copyright (C) 2011 Novell Co.
  16. * Jan Beulich <[email protected]>
  17. * Copyright (C) 2011-2012 Oracle Co.
  18. * Liang Tang <[email protected]>
  19. * Copyright (c) 2014 Oracle Co., Daniel Kiper
  20. */
  21. #include <linux/bug.h>
  22. #include <linux/efi.h>
  23. #include <linux/init.h>
  24. #include <linux/string.h>
  25. #include <xen/interface/xen.h>
  26. #include <xen/interface/platform.h>
  27. #include <xen/xen.h>
  28. #include <xen/xen-ops.h>
  29. #include <asm/page.h>
  30. #include <asm/xen/hypercall.h>
  31. #define INIT_EFI_OP(name) \
  32. {.cmd = XENPF_efi_runtime_call, \
  33. .u.efi_runtime_call.function = XEN_EFI_##name, \
  34. .u.efi_runtime_call.misc = 0}
  35. #define efi_data(op) (op.u.efi_runtime_call)
  36. static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
  37. {
  38. struct xen_platform_op op = INIT_EFI_OP(get_time);
  39. if (HYPERVISOR_platform_op(&op) < 0)
  40. return EFI_UNSUPPORTED;
  41. if (tm) {
  42. BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_time.time));
  43. memcpy(tm, &efi_data(op).u.get_time.time, sizeof(*tm));
  44. }
  45. if (tc) {
  46. tc->resolution = efi_data(op).u.get_time.resolution;
  47. tc->accuracy = efi_data(op).u.get_time.accuracy;
  48. tc->sets_to_zero = !!(efi_data(op).misc &
  49. XEN_EFI_GET_TIME_SET_CLEARS_NS);
  50. }
  51. return efi_data(op).status;
  52. }
  53. static efi_status_t xen_efi_set_time(efi_time_t *tm)
  54. {
  55. struct xen_platform_op op = INIT_EFI_OP(set_time);
  56. BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time));
  57. memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm));
  58. if (HYPERVISOR_platform_op(&op) < 0)
  59. return EFI_UNSUPPORTED;
  60. return efi_data(op).status;
  61. }
  62. static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
  63. efi_bool_t *pending,
  64. efi_time_t *tm)
  65. {
  66. struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time);
  67. if (HYPERVISOR_platform_op(&op) < 0)
  68. return EFI_UNSUPPORTED;
  69. if (tm) {
  70. BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_wakeup_time));
  71. memcpy(tm, &efi_data(op).u.get_wakeup_time, sizeof(*tm));
  72. }
  73. if (enabled)
  74. *enabled = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED);
  75. if (pending)
  76. *pending = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_PENDING);
  77. return efi_data(op).status;
  78. }
  79. static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
  80. {
  81. struct xen_platform_op op = INIT_EFI_OP(set_wakeup_time);
  82. BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_wakeup_time));
  83. if (enabled)
  84. efi_data(op).misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE;
  85. if (tm)
  86. memcpy(&efi_data(op).u.set_wakeup_time, tm, sizeof(*tm));
  87. else
  88. efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
  89. if (HYPERVISOR_platform_op(&op) < 0)
  90. return EFI_UNSUPPORTED;
  91. return efi_data(op).status;
  92. }
  93. static efi_status_t xen_efi_get_variable(efi_char16_t *name, efi_guid_t *vendor,
  94. u32 *attr, unsigned long *data_size,
  95. void *data)
  96. {
  97. struct xen_platform_op op = INIT_EFI_OP(get_variable);
  98. set_xen_guest_handle(efi_data(op).u.get_variable.name, name);
  99. BUILD_BUG_ON(sizeof(*vendor) !=
  100. sizeof(efi_data(op).u.get_variable.vendor_guid));
  101. memcpy(&efi_data(op).u.get_variable.vendor_guid, vendor, sizeof(*vendor));
  102. efi_data(op).u.get_variable.size = *data_size;
  103. set_xen_guest_handle(efi_data(op).u.get_variable.data, data);
  104. if (HYPERVISOR_platform_op(&op) < 0)
  105. return EFI_UNSUPPORTED;
  106. *data_size = efi_data(op).u.get_variable.size;
  107. if (attr)
  108. *attr = efi_data(op).misc;
  109. return efi_data(op).status;
  110. }
  111. static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
  112. efi_char16_t *name,
  113. efi_guid_t *vendor)
  114. {
  115. struct xen_platform_op op = INIT_EFI_OP(get_next_variable_name);
  116. efi_data(op).u.get_next_variable_name.size = *name_size;
  117. set_xen_guest_handle(efi_data(op).u.get_next_variable_name.name, name);
  118. BUILD_BUG_ON(sizeof(*vendor) !=
  119. sizeof(efi_data(op).u.get_next_variable_name.vendor_guid));
  120. memcpy(&efi_data(op).u.get_next_variable_name.vendor_guid, vendor,
  121. sizeof(*vendor));
  122. if (HYPERVISOR_platform_op(&op) < 0)
  123. return EFI_UNSUPPORTED;
  124. *name_size = efi_data(op).u.get_next_variable_name.size;
  125. memcpy(vendor, &efi_data(op).u.get_next_variable_name.vendor_guid,
  126. sizeof(*vendor));
  127. return efi_data(op).status;
  128. }
  129. static efi_status_t xen_efi_set_variable(efi_char16_t *name, efi_guid_t *vendor,
  130. u32 attr, unsigned long data_size,
  131. void *data)
  132. {
  133. struct xen_platform_op op = INIT_EFI_OP(set_variable);
  134. set_xen_guest_handle(efi_data(op).u.set_variable.name, name);
  135. efi_data(op).misc = attr;
  136. BUILD_BUG_ON(sizeof(*vendor) !=
  137. sizeof(efi_data(op).u.set_variable.vendor_guid));
  138. memcpy(&efi_data(op).u.set_variable.vendor_guid, vendor, sizeof(*vendor));
  139. efi_data(op).u.set_variable.size = data_size;
  140. set_xen_guest_handle(efi_data(op).u.set_variable.data, data);
  141. if (HYPERVISOR_platform_op(&op) < 0)
  142. return EFI_UNSUPPORTED;
  143. return efi_data(op).status;
  144. }
  145. static efi_status_t xen_efi_query_variable_info(u32 attr, u64 *storage_space,
  146. u64 *remaining_space,
  147. u64 *max_variable_size)
  148. {
  149. struct xen_platform_op op = INIT_EFI_OP(query_variable_info);
  150. if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
  151. return EFI_UNSUPPORTED;
  152. efi_data(op).u.query_variable_info.attr = attr;
  153. if (HYPERVISOR_platform_op(&op) < 0)
  154. return EFI_UNSUPPORTED;
  155. *storage_space = efi_data(op).u.query_variable_info.max_store_size;
  156. *remaining_space = efi_data(op).u.query_variable_info.remain_store_size;
  157. *max_variable_size = efi_data(op).u.query_variable_info.max_size;
  158. return efi_data(op).status;
  159. }
  160. static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
  161. {
  162. struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count);
  163. if (HYPERVISOR_platform_op(&op) < 0)
  164. return EFI_UNSUPPORTED;
  165. *count = efi_data(op).misc;
  166. return efi_data(op).status;
  167. }
  168. static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules,
  169. unsigned long count, unsigned long sg_list)
  170. {
  171. struct xen_platform_op op = INIT_EFI_OP(update_capsule);
  172. if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
  173. return EFI_UNSUPPORTED;
  174. set_xen_guest_handle(efi_data(op).u.update_capsule.capsule_header_array,
  175. capsules);
  176. efi_data(op).u.update_capsule.capsule_count = count;
  177. efi_data(op).u.update_capsule.sg_list = sg_list;
  178. if (HYPERVISOR_platform_op(&op) < 0)
  179. return EFI_UNSUPPORTED;
  180. return efi_data(op).status;
  181. }
  182. static efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules,
  183. unsigned long count, u64 *max_size, int *reset_type)
  184. {
  185. struct xen_platform_op op = INIT_EFI_OP(query_capsule_capabilities);
  186. if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
  187. return EFI_UNSUPPORTED;
  188. set_xen_guest_handle(efi_data(op).u.query_capsule_capabilities.capsule_header_array,
  189. capsules);
  190. efi_data(op).u.query_capsule_capabilities.capsule_count = count;
  191. if (HYPERVISOR_platform_op(&op) < 0)
  192. return EFI_UNSUPPORTED;
  193. *max_size = efi_data(op).u.query_capsule_capabilities.max_capsule_size;
  194. *reset_type = efi_data(op).u.query_capsule_capabilities.reset_type;
  195. return efi_data(op).status;
  196. }
  197. static void xen_efi_reset_system(int reset_type, efi_status_t status,
  198. unsigned long data_size, efi_char16_t *data)
  199. {
  200. switch (reset_type) {
  201. case EFI_RESET_COLD:
  202. case EFI_RESET_WARM:
  203. xen_reboot(SHUTDOWN_reboot);
  204. break;
  205. case EFI_RESET_SHUTDOWN:
  206. xen_reboot(SHUTDOWN_poweroff);
  207. break;
  208. default:
  209. BUG();
  210. }
  211. }
  212. /*
  213. * Set XEN EFI runtime services function pointers. Other fields of struct efi,
  214. * e.g. efi.systab, will be set like normal EFI.
  215. */
  216. void __init xen_efi_runtime_setup(void)
  217. {
  218. efi.get_time = xen_efi_get_time;
  219. efi.set_time = xen_efi_set_time;
  220. efi.get_wakeup_time = xen_efi_get_wakeup_time;
  221. efi.set_wakeup_time = xen_efi_set_wakeup_time;
  222. efi.get_variable = xen_efi_get_variable;
  223. efi.get_next_variable = xen_efi_get_next_variable;
  224. efi.set_variable = xen_efi_set_variable;
  225. efi.set_variable_nonblocking = xen_efi_set_variable;
  226. efi.query_variable_info = xen_efi_query_variable_info;
  227. efi.query_variable_info_nonblocking = xen_efi_query_variable_info;
  228. efi.update_capsule = xen_efi_update_capsule;
  229. efi.query_capsule_caps = xen_efi_query_capsule_caps;
  230. efi.get_next_high_mono_count = xen_efi_get_next_high_mono_count;
  231. efi.reset_system = xen_efi_reset_system;
  232. }