sgx.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * SGX common code
  3. *
  4. * Copyright (C) 2021 Intel Corporation
  5. *
  6. * Authors:
  7. * Yang Zhong<yang.zhong@intel.com>
  8. * Sean Christopherson <sean.j.christopherson@intel.com>
  9. *
  10. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  11. * See the COPYING file in the top-level directory.
  12. */
  13. #include "qemu/osdep.h"
  14. #include "hw/i386/pc.h"
  15. #include "hw/i386/sgx-epc.h"
  16. #include "hw/mem/memory-device.h"
  17. #include "monitor/qdev.h"
  18. #include "monitor/monitor.h"
  19. #include "monitor/hmp-target.h"
  20. #include "qapi/error.h"
  21. #include "qemu/error-report.h"
  22. #include "qapi/qapi-commands-misc-target.h"
  23. #include "exec/address-spaces.h"
  24. #include "system/hw_accel.h"
  25. #include "system/reset.h"
  26. #include <sys/ioctl.h>
  27. #include "hw/acpi/aml-build.h"
  28. #define SGX_MAX_EPC_SECTIONS 8
  29. #define SGX_CPUID_EPC_INVALID 0x0
  30. /* A valid EPC section. */
  31. #define SGX_CPUID_EPC_SECTION 0x1
  32. #define SGX_CPUID_EPC_MASK 0xF
  33. #define SGX_MAGIC 0xA4
  34. #define SGX_IOC_VEPC_REMOVE_ALL _IO(SGX_MAGIC, 0x04)
  35. #define RETRY_NUM 2
  36. static int sgx_epc_device_list(Object *obj, void *opaque)
  37. {
  38. GSList **list = opaque;
  39. if (object_dynamic_cast(obj, TYPE_SGX_EPC)) {
  40. *list = g_slist_append(*list, DEVICE(obj));
  41. }
  42. object_child_foreach(obj, sgx_epc_device_list, opaque);
  43. return 0;
  44. }
  45. static GSList *sgx_epc_get_device_list(void)
  46. {
  47. GSList *list = NULL;
  48. object_child_foreach(qdev_get_machine(), sgx_epc_device_list, &list);
  49. return list;
  50. }
  51. void sgx_epc_build_srat(GArray *table_data)
  52. {
  53. GSList *device_list = sgx_epc_get_device_list();
  54. for (; device_list; device_list = device_list->next) {
  55. DeviceState *dev = device_list->data;
  56. Object *obj = OBJECT(dev);
  57. uint64_t addr, size;
  58. int node;
  59. node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP,
  60. &error_abort);
  61. addr = object_property_get_uint(obj, SGX_EPC_ADDR_PROP, &error_abort);
  62. size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP, &error_abort);
  63. build_srat_memory(table_data, addr, size, node, MEM_AFFINITY_ENABLED);
  64. }
  65. g_slist_free(device_list);
  66. }
  67. static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high)
  68. {
  69. return (low & MAKE_64BIT_MASK(12, 20)) +
  70. ((high & MAKE_64BIT_MASK(0, 20)) << 32);
  71. }
  72. static SGXEPCSectionList *sgx_calc_host_epc_sections(void)
  73. {
  74. SGXEPCSectionList *head = NULL, **tail = &head;
  75. SGXEPCSection *section;
  76. uint32_t i, type;
  77. uint32_t eax, ebx, ecx, edx;
  78. uint32_t j = 0;
  79. for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) {
  80. host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx);
  81. type = eax & SGX_CPUID_EPC_MASK;
  82. if (type == SGX_CPUID_EPC_INVALID) {
  83. break;
  84. }
  85. if (type != SGX_CPUID_EPC_SECTION) {
  86. break;
  87. }
  88. section = g_new0(SGXEPCSection, 1);
  89. section->node = j++;
  90. section->size = sgx_calc_section_metric(ecx, edx);
  91. QAPI_LIST_APPEND(tail, section);
  92. }
  93. return head;
  94. }
  95. static void sgx_epc_reset(void *opaque)
  96. {
  97. PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
  98. HostMemoryBackend *hostmem;
  99. SGXEPCDevice *epc;
  100. int failures;
  101. int fd, i, j, r;
  102. static bool warned = false;
  103. /*
  104. * The second pass is needed to remove SECS pages that could not
  105. * be removed during the first.
  106. */
  107. for (i = 0; i < RETRY_NUM; i++) {
  108. failures = 0;
  109. for (j = 0; j < pcms->sgx_epc.nr_sections; j++) {
  110. epc = pcms->sgx_epc.sections[j];
  111. hostmem = MEMORY_BACKEND(epc->hostmem);
  112. fd = memory_region_get_fd(host_memory_backend_get_memory(hostmem));
  113. r = ioctl(fd, SGX_IOC_VEPC_REMOVE_ALL);
  114. if (r == -ENOTTY && !warned) {
  115. warned = true;
  116. warn_report("kernel does not support SGX_IOC_VEPC_REMOVE_ALL");
  117. warn_report("SGX might operate incorrectly in the guest after reset");
  118. break;
  119. } else if (r > 0) {
  120. /* SECS pages remain */
  121. failures++;
  122. if (i == 1) {
  123. error_report("cannot reset vEPC section %d", j);
  124. }
  125. }
  126. }
  127. if (!failures) {
  128. break;
  129. }
  130. }
  131. }
  132. SGXInfo *qmp_query_sgx_capabilities(Error **errp)
  133. {
  134. SGXInfo *info = NULL;
  135. uint32_t eax, ebx, ecx, edx;
  136. Error *local_err = NULL;
  137. int fd = qemu_open("/dev/sgx_vepc", O_RDWR, &local_err);
  138. if (fd < 0) {
  139. error_append_hint(&local_err, "SGX is not enabled in KVM");
  140. error_propagate(errp, local_err);
  141. return NULL;
  142. }
  143. info = g_new0(SGXInfo, 1);
  144. host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx);
  145. info->sgx = ebx & (1U << 2) ? true : false;
  146. info->flc = ecx & (1U << 30) ? true : false;
  147. host_cpuid(0x12, 0, &eax, &ebx, &ecx, &edx);
  148. info->sgx1 = eax & (1U << 0) ? true : false;
  149. info->sgx2 = eax & (1U << 1) ? true : false;
  150. info->sections = sgx_calc_host_epc_sections();
  151. close(fd);
  152. return info;
  153. }
  154. static SGXEPCSectionList *sgx_get_epc_sections_list(void)
  155. {
  156. GSList *device_list = sgx_epc_get_device_list();
  157. SGXEPCSectionList *head = NULL, **tail = &head;
  158. SGXEPCSection *section;
  159. for (; device_list; device_list = device_list->next) {
  160. DeviceState *dev = device_list->data;
  161. Object *obj = OBJECT(dev);
  162. section = g_new0(SGXEPCSection, 1);
  163. section->node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP,
  164. &error_abort);
  165. section->size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP,
  166. &error_abort);
  167. QAPI_LIST_APPEND(tail, section);
  168. }
  169. g_slist_free(device_list);
  170. return head;
  171. }
  172. SGXInfo *qmp_query_sgx(Error **errp)
  173. {
  174. SGXInfo *info = NULL;
  175. X86MachineState *x86ms;
  176. PCMachineState *pcms =
  177. (PCMachineState *)object_dynamic_cast(qdev_get_machine(),
  178. TYPE_PC_MACHINE);
  179. if (!pcms) {
  180. error_setg(errp, "SGX is only supported on PC machines");
  181. return NULL;
  182. }
  183. x86ms = X86_MACHINE(pcms);
  184. if (!x86ms->sgx_epc_list) {
  185. error_setg(errp, "No EPC regions defined, SGX not available");
  186. return NULL;
  187. }
  188. info = g_new0(SGXInfo, 1);
  189. info->sgx = true;
  190. info->sgx1 = true;
  191. info->sgx2 = true;
  192. info->flc = true;
  193. info->sections = sgx_get_epc_sections_list();
  194. return info;
  195. }
  196. void hmp_info_sgx(Monitor *mon, const QDict *qdict)
  197. {
  198. Error *err = NULL;
  199. SGXEPCSectionList *section_list, *section;
  200. g_autoptr(SGXInfo) info = qmp_query_sgx(&err);
  201. uint64_t size = 0;
  202. if (err) {
  203. error_report_err(err);
  204. return;
  205. }
  206. monitor_printf(mon, "SGX support: %s\n",
  207. info->sgx ? "enabled" : "disabled");
  208. monitor_printf(mon, "SGX1 support: %s\n",
  209. info->sgx1 ? "enabled" : "disabled");
  210. monitor_printf(mon, "SGX2 support: %s\n",
  211. info->sgx2 ? "enabled" : "disabled");
  212. monitor_printf(mon, "FLC support: %s\n",
  213. info->flc ? "enabled" : "disabled");
  214. section_list = info->sections;
  215. for (section = section_list; section; section = section->next) {
  216. monitor_printf(mon, "NUMA node #%" PRId64 ": ",
  217. section->value->node);
  218. monitor_printf(mon, "size=%" PRIu64 "\n",
  219. section->value->size);
  220. size += section->value->size;
  221. }
  222. monitor_printf(mon, "total size=%" PRIu64 "\n",
  223. size);
  224. }
  225. bool check_sgx_support(void)
  226. {
  227. if (!object_dynamic_cast(qdev_get_machine(), TYPE_PC_MACHINE)) {
  228. return false;
  229. }
  230. return true;
  231. }
  232. bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
  233. {
  234. PCMachineState *pcms =
  235. (PCMachineState *)object_dynamic_cast(qdev_get_machine(),
  236. TYPE_PC_MACHINE);
  237. SGXEPCDevice *epc;
  238. if (!pcms || pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) {
  239. return true;
  240. }
  241. epc = pcms->sgx_epc.sections[section_nr];
  242. *addr = epc->addr;
  243. *size = memory_device_get_region_size(MEMORY_DEVICE(epc), &error_fatal);
  244. return false;
  245. }
  246. void pc_machine_init_sgx_epc(PCMachineState *pcms)
  247. {
  248. SGXEPCState *sgx_epc = &pcms->sgx_epc;
  249. X86MachineState *x86ms = X86_MACHINE(pcms);
  250. SgxEPCList *list = NULL;
  251. memset(sgx_epc, 0, sizeof(SGXEPCState));
  252. if (!x86ms->sgx_epc_list) {
  253. return;
  254. }
  255. sgx_epc->base = x86ms->above_4g_mem_start + x86ms->above_4g_mem_size;
  256. memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX);
  257. memory_region_add_subregion(get_system_memory(), sgx_epc->base,
  258. &sgx_epc->mr);
  259. for (list = x86ms->sgx_epc_list; list; list = list->next) {
  260. DeviceState *dev = qdev_new(TYPE_SGX_EPC);
  261. /* set the memdev link with memory backend */
  262. object_property_parse(OBJECT(dev), SGX_EPC_MEMDEV_PROP,
  263. list->value->memdev, &error_fatal);
  264. /* set the numa node property for sgx epc object */
  265. object_property_set_uint(OBJECT(dev), SGX_EPC_NUMA_NODE_PROP,
  266. list->value->node, &error_fatal);
  267. qdev_realize_and_unref(dev, NULL, &error_fatal);
  268. }
  269. if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) {
  270. error_report("Size of all 'sgx-epc' =0x%"PRIx64" causes EPC to wrap",
  271. sgx_epc->size);
  272. exit(EXIT_FAILURE);
  273. }
  274. memory_region_set_size(&sgx_epc->mr, sgx_epc->size);
  275. /* register the reset callback for sgx epc */
  276. qemu_register_reset(sgx_epc_reset, NULL);
  277. }