efi.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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 <drummond@valinux.com>
  7. * Copyright (C) 1999-2002 Hewlett-Packard Co.
  8. * David Mosberger-Tang <davidm@hpl.hp.com>
  9. * Stephane Eranian <eranian@hpl.hp.com>
  10. * Copyright (C) 2005-2008 Intel Co.
  11. * Fenghua Yu <fenghua.yu@intel.com>
  12. * Bibo Mao <bibo.mao@intel.com>
  13. * Chandramouli Narayanan <mouli@linux.intel.com>
  14. * Huang Ying <ying.huang@intel.com>
  15. * Copyright (C) 2011 Novell Co.
  16. * Jan Beulich <JBeulich@suse.com>
  17. * Copyright (C) 2011-2012 Oracle Co.
  18. * Liang Tang <liang.tang@oracle.com>
  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/page.h>
  28. #include <xen/xen.h>
  29. #include <xen/xen-ops.h>
  30. #include <asm/page.h>
  31. #include <asm/xen/hypercall.h>
  32. #define INIT_EFI_OP(name) \
  33. {.cmd = XENPF_efi_runtime_call, \
  34. .u.efi_runtime_call.function = XEN_EFI_##name, \
  35. .u.efi_runtime_call.misc = 0}
  36. #define efi_data(op) (op.u.efi_runtime_call)
  37. static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
  38. {
  39. struct xen_platform_op op = INIT_EFI_OP(get_time);
  40. if (HYPERVISOR_platform_op(&op) < 0)
  41. return EFI_UNSUPPORTED;
  42. if (tm) {
  43. BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_time.time));
  44. memcpy(tm, &efi_data(op).u.get_time.time, sizeof(*tm));
  45. }
  46. if (tc) {
  47. tc->resolution = efi_data(op).u.get_time.resolution;
  48. tc->accuracy = efi_data(op).u.get_time.accuracy;
  49. tc->sets_to_zero = !!(efi_data(op).misc &
  50. XEN_EFI_GET_TIME_SET_CLEARS_NS);
  51. }
  52. return efi_data(op).status;
  53. }
  54. static efi_status_t xen_efi_set_time(efi_time_t *tm)
  55. {
  56. struct xen_platform_op op = INIT_EFI_OP(set_time);
  57. BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time));
  58. memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm));
  59. if (HYPERVISOR_platform_op(&op) < 0)
  60. return EFI_UNSUPPORTED;
  61. return efi_data(op).status;
  62. }
  63. static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
  64. efi_bool_t *pending,
  65. efi_time_t *tm)
  66. {
  67. struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time);
  68. if (HYPERVISOR_platform_op(&op) < 0)
  69. return EFI_UNSUPPORTED;
  70. if (tm) {
  71. BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_wakeup_time));
  72. memcpy(tm, &efi_data(op).u.get_wakeup_time, sizeof(*tm));
  73. }
  74. if (enabled)
  75. *enabled = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED);
  76. if (pending)
  77. *pending = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_PENDING);
  78. return efi_data(op).status;
  79. }
  80. static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
  81. {
  82. struct xen_platform_op op = INIT_EFI_OP(set_wakeup_time);
  83. BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_wakeup_time));
  84. if (enabled)
  85. efi_data(op).misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE;
  86. if (tm)
  87. memcpy(&efi_data(op).u.set_wakeup_time, tm, sizeof(*tm));
  88. else
  89. efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
  90. if (HYPERVISOR_platform_op(&op) < 0)
  91. return EFI_UNSUPPORTED;
  92. return efi_data(op).status;
  93. }
  94. static efi_status_t xen_efi_get_variable(efi_char16_t *name, efi_guid_t *vendor,
  95. u32 *attr, unsigned long *data_size,
  96. void *data)
  97. {
  98. struct xen_platform_op op = INIT_EFI_OP(get_variable);
  99. set_xen_guest_handle(efi_data(op).u.get_variable.name, name);
  100. BUILD_BUG_ON(sizeof(*vendor) !=
  101. sizeof(efi_data(op).u.get_variable.vendor_guid));
  102. memcpy(&efi_data(op).u.get_variable.vendor_guid, vendor, sizeof(*vendor));
  103. efi_data(op).u.get_variable.size = *data_size;
  104. set_xen_guest_handle(efi_data(op).u.get_variable.data, data);
  105. if (HYPERVISOR_platform_op(&op) < 0)
  106. return EFI_UNSUPPORTED;
  107. *data_size = efi_data(op).u.get_variable.size;
  108. if (attr)
  109. *attr = efi_data(op).misc;
  110. return efi_data(op).status;
  111. }
  112. static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
  113. efi_char16_t *name,
  114. efi_guid_t *vendor)
  115. {
  116. struct xen_platform_op op = INIT_EFI_OP(get_next_variable_name);
  117. efi_data(op).u.get_next_variable_name.size = *name_size;
  118. set_xen_guest_handle(efi_data(op).u.get_next_variable_name.name, name);
  119. BUILD_BUG_ON(sizeof(*vendor) !=
  120. sizeof(efi_data(op).u.get_next_variable_name.vendor_guid));
  121. memcpy(&efi_data(op).u.get_next_variable_name.vendor_guid, vendor,
  122. sizeof(*vendor));
  123. if (HYPERVISOR_platform_op(&op) < 0)
  124. return EFI_UNSUPPORTED;
  125. *name_size = efi_data(op).u.get_next_variable_name.size;
  126. memcpy(vendor, &efi_data(op).u.get_next_variable_name.vendor_guid,
  127. sizeof(*vendor));
  128. return efi_data(op).status;
  129. }
  130. static efi_status_t xen_efi_set_variable(efi_char16_t *name, efi_guid_t *vendor,
  131. u32 attr, unsigned long data_size,
  132. void *data)
  133. {
  134. struct xen_platform_op op = INIT_EFI_OP(set_variable);
  135. set_xen_guest_handle(efi_data(op).u.set_variable.name, name);
  136. efi_data(op).misc = attr;
  137. BUILD_BUG_ON(sizeof(*vendor) !=
  138. sizeof(efi_data(op).u.set_variable.vendor_guid));
  139. memcpy(&efi_data(op).u.set_variable.vendor_guid, vendor, sizeof(*vendor));
  140. efi_data(op).u.set_variable.size = data_size;
  141. set_xen_guest_handle(efi_data(op).u.set_variable.data, data);
  142. if (HYPERVISOR_platform_op(&op) < 0)
  143. return EFI_UNSUPPORTED;
  144. return efi_data(op).status;
  145. }
  146. static efi_status_t xen_efi_query_variable_info(u32 attr, u64 *storage_space,
  147. u64 *remaining_space,
  148. u64 *max_variable_size)
  149. {
  150. struct xen_platform_op op = INIT_EFI_OP(query_variable_info);
  151. if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
  152. return EFI_UNSUPPORTED;
  153. efi_data(op).u.query_variable_info.attr = attr;
  154. if (HYPERVISOR_platform_op(&op) < 0)
  155. return EFI_UNSUPPORTED;
  156. *storage_space = efi_data(op).u.query_variable_info.max_store_size;
  157. *remaining_space = efi_data(op).u.query_variable_info.remain_store_size;
  158. *max_variable_size = efi_data(op).u.query_variable_info.max_size;
  159. return efi_data(op).status;
  160. }
  161. static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
  162. {
  163. struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count);
  164. if (HYPERVISOR_platform_op(&op) < 0)
  165. return EFI_UNSUPPORTED;
  166. *count = efi_data(op).misc;
  167. return efi_data(op).status;
  168. }
  169. static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules,
  170. unsigned long count, unsigned long sg_list)
  171. {
  172. struct xen_platform_op op = INIT_EFI_OP(update_capsule);
  173. if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
  174. return EFI_UNSUPPORTED;
  175. set_xen_guest_handle(efi_data(op).u.update_capsule.capsule_header_array,
  176. capsules);
  177. efi_data(op).u.update_capsule.capsule_count = count;
  178. efi_data(op).u.update_capsule.sg_list = sg_list;
  179. if (HYPERVISOR_platform_op(&op) < 0)
  180. return EFI_UNSUPPORTED;
  181. return efi_data(op).status;
  182. }
  183. static efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules,
  184. unsigned long count, u64 *max_size, int *reset_type)
  185. {
  186. struct xen_platform_op op = INIT_EFI_OP(query_capsule_capabilities);
  187. if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
  188. return EFI_UNSUPPORTED;
  189. set_xen_guest_handle(efi_data(op).u.query_capsule_capabilities.capsule_header_array,
  190. capsules);
  191. efi_data(op).u.query_capsule_capabilities.capsule_count = count;
  192. if (HYPERVISOR_platform_op(&op) < 0)
  193. return EFI_UNSUPPORTED;
  194. *max_size = efi_data(op).u.query_capsule_capabilities.max_capsule_size;
  195. *reset_type = efi_data(op).u.query_capsule_capabilities.reset_type;
  196. return efi_data(op).status;
  197. }
  198. static void xen_efi_reset_system(int reset_type, efi_status_t status,
  199. unsigned long data_size, efi_char16_t *data)
  200. {
  201. switch (reset_type) {
  202. case EFI_RESET_COLD:
  203. case EFI_RESET_WARM:
  204. xen_reboot(SHUTDOWN_reboot);
  205. break;
  206. case EFI_RESET_SHUTDOWN:
  207. xen_reboot(SHUTDOWN_poweroff);
  208. break;
  209. default:
  210. BUG();
  211. }
  212. }
  213. /*
  214. * Set XEN EFI runtime services function pointers. Other fields of struct efi,
  215. * e.g. efi.systab, will be set like normal EFI.
  216. */
  217. void __init xen_efi_runtime_setup(void)
  218. {
  219. efi.get_time = xen_efi_get_time;
  220. efi.set_time = xen_efi_set_time;
  221. efi.get_wakeup_time = xen_efi_get_wakeup_time;
  222. efi.set_wakeup_time = xen_efi_set_wakeup_time;
  223. efi.get_variable = xen_efi_get_variable;
  224. efi.get_next_variable = xen_efi_get_next_variable;
  225. efi.set_variable = xen_efi_set_variable;
  226. efi.set_variable_nonblocking = xen_efi_set_variable;
  227. efi.query_variable_info = xen_efi_query_variable_info;
  228. efi.query_variable_info_nonblocking = xen_efi_query_variable_info;
  229. efi.update_capsule = xen_efi_update_capsule;
  230. efi.query_capsule_caps = xen_efi_query_capsule_caps;
  231. efi.get_next_high_mono_count = xen_efi_get_next_high_mono_count;
  232. efi.reset_system = xen_efi_reset_system;
  233. }
  234. int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
  235. {
  236. static_assert(XEN_PAGE_SHIFT == EFI_PAGE_SHIFT,
  237. "Mismatch between EFI_PAGE_SHIFT and XEN_PAGE_SHIFT");
  238. struct xen_platform_op op;
  239. union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
  240. int rc;
  241. if (!efi_enabled(EFI_PARAVIRT) || efi_enabled(EFI_MEMMAP))
  242. return __efi_mem_desc_lookup(phys_addr, out_md);
  243. phys_addr &= ~(u64)(EFI_PAGE_SIZE - 1);
  244. op = (struct xen_platform_op) {
  245. .cmd = XENPF_firmware_info,
  246. .u.firmware_info = {
  247. .type = XEN_FW_EFI_INFO,
  248. .index = XEN_FW_EFI_MEM_INFO,
  249. .u.efi_info.mem.addr = phys_addr,
  250. .u.efi_info.mem.size = U64_MAX - phys_addr,
  251. },
  252. };
  253. rc = HYPERVISOR_platform_op(&op);
  254. if (rc) {
  255. pr_warn("Failed to lookup header 0x%llx in Xen memory map: error %d\n",
  256. phys_addr, rc);
  257. }
  258. out_md->phys_addr = info->mem.addr;
  259. out_md->num_pages = info->mem.size >> EFI_PAGE_SHIFT;
  260. out_md->type = info->mem.type;
  261. out_md->attribute = info->mem.attr;
  262. return 0;
  263. }
  264. bool __init xen_efi_config_table_is_usable(const efi_guid_t *guid,
  265. unsigned long table)
  266. {
  267. efi_memory_desc_t md;
  268. int rc;
  269. if (!efi_enabled(EFI_PARAVIRT))
  270. return true;
  271. rc = efi_mem_desc_lookup(table, &md);
  272. if (rc)
  273. return false;
  274. switch (md.type) {
  275. case EFI_RUNTIME_SERVICES_CODE:
  276. case EFI_RUNTIME_SERVICES_DATA:
  277. case EFI_ACPI_RECLAIM_MEMORY:
  278. case EFI_ACPI_MEMORY_NVS:
  279. case EFI_RESERVED_TYPE:
  280. return true;
  281. default:
  282. return false;
  283. }
  284. }