efi_variable_tee.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * EFI variable service via OP-TEE
  4. *
  5. * Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org>
  6. * Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org>
  7. * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
  8. *
  9. * Authors:
  10. * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
  11. */
  12. #include <common.h>
  13. #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
  14. #include <arm_ffa.h>
  15. #endif
  16. #include <cpu_func.h>
  17. #include <dm.h>
  18. #include <efi.h>
  19. #include <efi_api.h>
  20. #include <efi_loader.h>
  21. #include <efi_variable.h>
  22. #include <malloc.h>
  23. #include <mapmem.h>
  24. #include <mm_communication.h>
  25. #include <tee.h>
  26. #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
  27. /* MM return codes */
  28. #define MM_SUCCESS (0)
  29. #define MM_NOT_SUPPORTED (-1)
  30. #define MM_INVALID_PARAMETER (-2)
  31. #define MM_DENIED (-3)
  32. #define MM_NO_MEMORY (-5)
  33. static const char *mm_sp_svc_uuid = MM_SP_UUID;
  34. static u16 mm_sp_id;
  35. #endif
  36. extern struct efi_var_file __efi_runtime_data *efi_var_buf;
  37. static efi_uintn_t max_buffer_size; /* comm + var + func + data */
  38. static efi_uintn_t max_payload_size; /* func + data */
  39. struct mm_connection {
  40. struct udevice *tee;
  41. u32 session;
  42. };
  43. /**
  44. * get_connection() - Retrieve OP-TEE session for a specific UUID.
  45. *
  46. * @conn: session buffer to fill
  47. * Return: status code
  48. */
  49. static int get_connection(struct mm_connection *conn)
  50. {
  51. static const struct tee_optee_ta_uuid uuid = PTA_STMM_UUID;
  52. struct udevice *tee = NULL;
  53. struct tee_open_session_arg arg;
  54. int rc = -ENODEV;
  55. tee = tee_find_device(tee, NULL, NULL, NULL);
  56. if (!tee)
  57. goto out;
  58. memset(&arg, 0, sizeof(arg));
  59. tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
  60. rc = tee_open_session(tee, &arg, 0, NULL);
  61. if (rc)
  62. goto out;
  63. /* Check the internal OP-TEE result */
  64. if (arg.ret != TEE_SUCCESS) {
  65. rc = -EIO;
  66. goto out;
  67. }
  68. conn->tee = tee;
  69. conn->session = arg.session;
  70. return 0;
  71. out:
  72. return rc;
  73. }
  74. /**
  75. * optee_mm_communicate() - Pass a buffer to StandaloneMM running in OP-TEE
  76. *
  77. * @comm_buf: locally allocted communcation buffer
  78. * @dsize: buffer size
  79. * Return: status code
  80. */
  81. static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
  82. {
  83. ulong buf_size;
  84. efi_status_t ret;
  85. struct efi_mm_communicate_header *mm_hdr;
  86. struct mm_connection conn = { NULL, 0 };
  87. struct tee_invoke_arg arg;
  88. struct tee_param param[2];
  89. struct tee_shm *shm = NULL;
  90. int rc;
  91. if (!comm_buf)
  92. return EFI_INVALID_PARAMETER;
  93. mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
  94. buf_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t);
  95. if (dsize != buf_size)
  96. return EFI_INVALID_PARAMETER;
  97. rc = get_connection(&conn);
  98. if (rc) {
  99. log_err("Unable to open OP-TEE session (err=%d)\n", rc);
  100. return EFI_UNSUPPORTED;
  101. }
  102. if (tee_shm_register(conn.tee, comm_buf, buf_size, 0, &shm)) {
  103. log_err("Unable to register shared memory\n");
  104. tee_close_session(conn.tee, conn.session);
  105. return EFI_UNSUPPORTED;
  106. }
  107. memset(&arg, 0, sizeof(arg));
  108. arg.func = PTA_STMM_CMDID_COMMUNICATE;
  109. arg.session = conn.session;
  110. memset(param, 0, sizeof(param));
  111. param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
  112. param[0].u.memref.size = buf_size;
  113. param[0].u.memref.shm = shm;
  114. param[1].attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
  115. rc = tee_invoke_func(conn.tee, &arg, 2, param);
  116. tee_shm_free(shm);
  117. tee_close_session(conn.tee, conn.session);
  118. if (rc)
  119. return EFI_DEVICE_ERROR;
  120. if (arg.ret == TEE_ERROR_EXCESS_DATA)
  121. log_err("Variable payload too large\n");
  122. if (arg.ret != TEE_SUCCESS)
  123. return EFI_DEVICE_ERROR;
  124. switch (param[1].u.value.a) {
  125. case ARM_SVC_SPM_RET_SUCCESS:
  126. ret = EFI_SUCCESS;
  127. break;
  128. case ARM_SVC_SPM_RET_INVALID_PARAMS:
  129. ret = EFI_INVALID_PARAMETER;
  130. break;
  131. case ARM_SVC_SPM_RET_DENIED:
  132. ret = EFI_ACCESS_DENIED;
  133. break;
  134. case ARM_SVC_SPM_RET_NO_MEMORY:
  135. ret = EFI_OUT_OF_RESOURCES;
  136. break;
  137. default:
  138. ret = EFI_ACCESS_DENIED;
  139. }
  140. return ret;
  141. }
  142. #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
  143. /**
  144. * ffa_notify_mm_sp() - Announce there is data in the shared buffer
  145. *
  146. * Notify the MM partition in the trusted world that
  147. * data is available in the shared buffer.
  148. * This is a blocking call during which trusted world has exclusive access
  149. * to the MM shared buffer.
  150. *
  151. * Return:
  152. *
  153. * 0 on success
  154. */
  155. static int ffa_notify_mm_sp(void)
  156. {
  157. struct ffa_send_direct_data msg = {0};
  158. int ret;
  159. int sp_event_ret;
  160. struct udevice *dev;
  161. ret = uclass_first_device_err(UCLASS_FFA, &dev);
  162. if (ret) {
  163. log_err("EFI: Cannot find FF-A bus device, notify MM SP failure\n");
  164. return ret;
  165. }
  166. msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET; /* x3 */
  167. ret = ffa_sync_send_receive(dev, mm_sp_id, &msg, 1);
  168. if (ret)
  169. return ret;
  170. sp_event_ret = msg.data0; /* x3 */
  171. switch (sp_event_ret) {
  172. case MM_SUCCESS:
  173. ret = 0;
  174. break;
  175. case MM_NOT_SUPPORTED:
  176. ret = -EINVAL;
  177. break;
  178. case MM_INVALID_PARAMETER:
  179. ret = -EPERM;
  180. break;
  181. case MM_DENIED:
  182. ret = -EACCES;
  183. break;
  184. case MM_NO_MEMORY:
  185. ret = -EBUSY;
  186. break;
  187. default:
  188. ret = -EACCES;
  189. }
  190. return ret;
  191. }
  192. /**
  193. * ffa_discover_mm_sp_id() - Query the MM partition ID
  194. *
  195. * Use the FF-A driver to get the MM partition ID.
  196. * If multiple partitions are found, use the first one.
  197. * This is a boot time function.
  198. *
  199. * Return:
  200. *
  201. * 0 on success
  202. */
  203. static int ffa_discover_mm_sp_id(void)
  204. {
  205. u32 count = 0;
  206. int ret;
  207. struct ffa_partition_desc *descs;
  208. struct udevice *dev;
  209. ret = uclass_first_device_err(UCLASS_FFA, &dev);
  210. if (ret) {
  211. log_err("EFI: Cannot find FF-A bus device, MM SP discovery failure\n");
  212. return ret;
  213. }
  214. /* Ask the driver to fill the buffer with the SPs info */
  215. ret = ffa_partition_info_get(dev, mm_sp_svc_uuid, &count, &descs);
  216. if (ret) {
  217. log_err("EFI: Failure in querying SPs info (%d), MM SP discovery failure\n", ret);
  218. return ret;
  219. }
  220. /* MM SPs found , use the first one */
  221. mm_sp_id = descs[0].info.id;
  222. log_info("EFI: MM partition ID 0x%x\n", mm_sp_id);
  223. return 0;
  224. }
  225. /**
  226. * ffa_mm_communicate() - Exchange EFI services data with the MM partition using FF-A
  227. * @comm_buf: locally allocated communication buffer used for rx/tx
  228. * @dsize: communication buffer size
  229. *
  230. * Issue a door bell event to notify the MM partition (SP) running in OP-TEE
  231. * that there is data to read from the shared buffer.
  232. * Communication with the MM SP is performed using FF-A transport.
  233. * On the event, MM SP can read the data from the buffer and
  234. * update the MM shared buffer with response data.
  235. * The response data is copied back to the communication buffer.
  236. *
  237. * Return:
  238. *
  239. * EFI status code
  240. */
  241. static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
  242. {
  243. ulong tx_data_size;
  244. int ffa_ret;
  245. efi_status_t efi_ret;
  246. struct efi_mm_communicate_header *mm_hdr;
  247. void *virt_shared_buf;
  248. if (!comm_buf)
  249. return EFI_INVALID_PARAMETER;
  250. /* Discover MM partition ID at boot time */
  251. if (!mm_sp_id && ffa_discover_mm_sp_id()) {
  252. log_err("EFI: Failure to discover MM SP ID at boot time, FF-A MM comms failure\n");
  253. return EFI_UNSUPPORTED;
  254. }
  255. mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
  256. tx_data_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t);
  257. if (comm_buf_size != tx_data_size || tx_data_size > CONFIG_FFA_SHARED_MM_BUF_SIZE)
  258. return EFI_INVALID_PARAMETER;
  259. /* Copy the data to the shared buffer */
  260. virt_shared_buf = map_sysmem((phys_addr_t)CONFIG_FFA_SHARED_MM_BUF_ADDR, 0);
  261. memcpy(virt_shared_buf, comm_buf, tx_data_size);
  262. /*
  263. * The secure world might have cache disabled for
  264. * the device region used for shared buffer (which is the case for Optee).
  265. * In this case, the secure world reads the data from DRAM.
  266. * Let's flush the cache so the DRAM is updated with the latest data.
  267. */
  268. #ifdef CONFIG_ARM64
  269. invalidate_dcache_all();
  270. #endif
  271. /* Announce there is data in the shared buffer */
  272. ffa_ret = ffa_notify_mm_sp();
  273. switch (ffa_ret) {
  274. case 0: {
  275. ulong rx_data_size;
  276. /* Copy the MM SP response from the shared buffer to the communication buffer */
  277. rx_data_size = ((struct efi_mm_communicate_header *)virt_shared_buf)->message_len +
  278. sizeof(efi_guid_t) +
  279. sizeof(size_t);
  280. if (rx_data_size > comm_buf_size) {
  281. efi_ret = EFI_OUT_OF_RESOURCES;
  282. break;
  283. }
  284. memcpy(comm_buf, virt_shared_buf, rx_data_size);
  285. efi_ret = EFI_SUCCESS;
  286. break;
  287. }
  288. case -EINVAL:
  289. efi_ret = EFI_DEVICE_ERROR;
  290. break;
  291. case -EPERM:
  292. efi_ret = EFI_INVALID_PARAMETER;
  293. break;
  294. case -EACCES:
  295. efi_ret = EFI_ACCESS_DENIED;
  296. break;
  297. case -EBUSY:
  298. efi_ret = EFI_OUT_OF_RESOURCES;
  299. break;
  300. default:
  301. efi_ret = EFI_ACCESS_DENIED;
  302. }
  303. unmap_sysmem(virt_shared_buf);
  304. return efi_ret;
  305. }
  306. /**
  307. * get_mm_comms() - detect the available MM transport
  308. *
  309. * Make sure the FF-A bus is probed successfully
  310. * which means FF-A communication with secure world works and ready
  311. * for use.
  312. *
  313. * If FF-A bus is not ready, use OPTEE comms.
  314. *
  315. * Return:
  316. *
  317. * MM_COMMS_FFA or MM_COMMS_OPTEE
  318. */
  319. static enum mm_comms_select get_mm_comms(void)
  320. {
  321. struct udevice *dev;
  322. int ret;
  323. ret = uclass_first_device_err(UCLASS_FFA, &dev);
  324. if (ret) {
  325. log_debug("EFI: Cannot find FF-A bus device, trying Optee comms\n");
  326. return MM_COMMS_OPTEE;
  327. }
  328. return MM_COMMS_FFA;
  329. }
  330. #endif
  331. /**
  332. * mm_communicate() - Adjust the communication buffer to the MM SP and send
  333. * it to OP-TEE
  334. *
  335. * @comm_buf: locally allocated communication buffer
  336. * @dsize: buffer size
  337. *
  338. * The SP (also called partition) can be any MM SP such as StandAlonneMM or smm-gateway.
  339. * The comm_buf format is the same for both partitions.
  340. * When using the u-boot OP-TEE driver, StandAlonneMM is supported.
  341. * When using the u-boot FF-A driver, any MM SP is supported.
  342. *
  343. * Return: status code
  344. */
  345. static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
  346. {
  347. efi_status_t ret;
  348. struct efi_mm_communicate_header *mm_hdr;
  349. struct smm_variable_communicate_header *var_hdr;
  350. #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
  351. enum mm_comms_select mm_comms;
  352. #endif
  353. dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE;
  354. mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
  355. var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
  356. #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
  357. mm_comms = get_mm_comms();
  358. if (mm_comms == MM_COMMS_FFA)
  359. ret = ffa_mm_communicate(comm_buf, dsize);
  360. else
  361. ret = optee_mm_communicate(comm_buf, dsize);
  362. #else
  363. ret = optee_mm_communicate(comm_buf, dsize);
  364. #endif
  365. if (ret != EFI_SUCCESS) {
  366. log_err("%s failed!\n", __func__);
  367. return ret;
  368. }
  369. return var_hdr->ret_status;
  370. }
  371. /**
  372. * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the
  373. * header data.
  374. *
  375. * @dptr: pointer address of the corresponding StandAloneMM
  376. * function
  377. * @payload_size: buffer size
  378. * @func: standAloneMM function number
  379. * @ret: EFI return code
  380. * Return: buffer or NULL
  381. */
  382. static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
  383. efi_uintn_t func, efi_status_t *ret)
  384. {
  385. const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID;
  386. struct efi_mm_communicate_header *mm_hdr;
  387. struct smm_variable_communicate_header *var_hdr;
  388. u8 *comm_buf;
  389. /* In the init function we initialize max_buffer_size with
  390. * get_max_payload(). So skip the test if max_buffer_size is initialized
  391. * StandAloneMM will perform similar checks and drop the buffer if it's
  392. * too long
  393. */
  394. if (max_buffer_size && max_buffer_size <
  395. (MM_COMMUNICATE_HEADER_SIZE +
  396. MM_VARIABLE_COMMUNICATE_SIZE +
  397. payload_size)) {
  398. *ret = EFI_INVALID_PARAMETER;
  399. return NULL;
  400. }
  401. comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
  402. MM_VARIABLE_COMMUNICATE_SIZE +
  403. payload_size);
  404. if (!comm_buf) {
  405. *ret = EFI_OUT_OF_RESOURCES;
  406. return NULL;
  407. }
  408. mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
  409. guidcpy(&mm_hdr->header_guid, &mm_var_guid);
  410. mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size;
  411. var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
  412. var_hdr->function = func;
  413. if (dptr)
  414. *dptr = var_hdr->data;
  415. *ret = EFI_SUCCESS;
  416. return comm_buf;
  417. }
  418. /**
  419. * get_max_payload() - Get variable payload size from StandAloneMM.
  420. *
  421. * @size: size of the variable in storage
  422. * Return: status code
  423. */
  424. efi_status_t EFIAPI get_max_payload(efi_uintn_t *size)
  425. {
  426. struct smm_variable_payload_size *var_payload = NULL;
  427. efi_uintn_t payload_size;
  428. u8 *comm_buf = NULL;
  429. efi_status_t ret;
  430. if (!size) {
  431. ret = EFI_INVALID_PARAMETER;
  432. goto out;
  433. }
  434. payload_size = sizeof(*var_payload);
  435. comm_buf = setup_mm_hdr((void **)&var_payload, payload_size,
  436. SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, &ret);
  437. if (!comm_buf)
  438. goto out;
  439. ret = mm_communicate(comm_buf, payload_size);
  440. if (ret != EFI_SUCCESS)
  441. goto out;
  442. /* Make sure the buffer is big enough for storing variables */
  443. if (var_payload->size < MM_VARIABLE_ACCESS_HEADER_SIZE + 0x20) {
  444. ret = EFI_DEVICE_ERROR;
  445. goto out;
  446. }
  447. *size = var_payload->size;
  448. /*
  449. * There seems to be a bug in EDK2 miscalculating the boundaries and
  450. * size checks, so deduct 2 more bytes to fulfill this requirement. Fix
  451. * it up here to ensure backwards compatibility with older versions
  452. * (cf. StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c.
  453. * sizeof (EFI_MM_COMMUNICATE_HEADER) instead the size minus the
  454. * flexible array member).
  455. *
  456. * size is guaranteed to be > 2 due to checks on the beginning.
  457. */
  458. *size -= 2;
  459. out:
  460. free(comm_buf);
  461. return ret;
  462. }
  463. /*
  464. * StMM can store internal attributes and properties for variables, i.e enabling
  465. * R/O variables
  466. */
  467. static efi_status_t set_property_int(const u16 *variable_name,
  468. efi_uintn_t name_size,
  469. const efi_guid_t *vendor,
  470. struct var_check_property *var_property)
  471. {
  472. struct smm_variable_var_check_property *smm_property;
  473. efi_uintn_t payload_size;
  474. u8 *comm_buf = NULL;
  475. efi_status_t ret;
  476. payload_size = sizeof(*smm_property) + name_size;
  477. if (payload_size > max_payload_size) {
  478. ret = EFI_INVALID_PARAMETER;
  479. goto out;
  480. }
  481. comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
  482. SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET,
  483. &ret);
  484. if (!comm_buf)
  485. goto out;
  486. guidcpy(&smm_property->guid, vendor);
  487. smm_property->name_size = name_size;
  488. memcpy(&smm_property->property, var_property,
  489. sizeof(smm_property->property));
  490. memcpy(smm_property->name, variable_name, name_size);
  491. ret = mm_communicate(comm_buf, payload_size);
  492. out:
  493. free(comm_buf);
  494. return ret;
  495. }
  496. static efi_status_t get_property_int(const u16 *variable_name,
  497. efi_uintn_t name_size,
  498. const efi_guid_t *vendor,
  499. struct var_check_property *var_property)
  500. {
  501. struct smm_variable_var_check_property *smm_property;
  502. efi_uintn_t payload_size;
  503. u8 *comm_buf = NULL;
  504. efi_status_t ret;
  505. memset(var_property, 0, sizeof(*var_property));
  506. payload_size = sizeof(*smm_property) + name_size;
  507. if (payload_size > max_payload_size) {
  508. ret = EFI_INVALID_PARAMETER;
  509. goto out;
  510. }
  511. comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
  512. SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET,
  513. &ret);
  514. if (!comm_buf)
  515. goto out;
  516. guidcpy(&smm_property->guid, vendor);
  517. smm_property->name_size = name_size;
  518. memcpy(smm_property->name, variable_name, name_size);
  519. ret = mm_communicate(comm_buf, payload_size);
  520. /*
  521. * Currently only R/O property is supported in StMM.
  522. * Variables that are not set to R/O will not set the property in StMM
  523. * and the call will return EFI_NOT_FOUND. We are setting the
  524. * properties to 0x0 so checking against that is enough for the
  525. * EFI_NOT_FOUND case.
  526. */
  527. if (ret == EFI_NOT_FOUND)
  528. ret = EFI_SUCCESS;
  529. if (ret != EFI_SUCCESS)
  530. goto out;
  531. memcpy(var_property, &smm_property->property, sizeof(*var_property));
  532. out:
  533. free(comm_buf);
  534. return ret;
  535. }
  536. efi_status_t efi_get_variable_int(const u16 *variable_name,
  537. const efi_guid_t *vendor,
  538. u32 *attributes, efi_uintn_t *data_size,
  539. void *data, u64 *timep)
  540. {
  541. struct var_check_property var_property;
  542. struct smm_variable_access *var_acc;
  543. efi_uintn_t payload_size;
  544. efi_uintn_t name_size;
  545. efi_uintn_t tmp_dsize;
  546. u8 *comm_buf = NULL;
  547. efi_status_t ret, tmp;
  548. if (!variable_name || !vendor || !data_size) {
  549. ret = EFI_INVALID_PARAMETER;
  550. goto out;
  551. }
  552. /* Check payload size */
  553. name_size = u16_strsize(variable_name);
  554. if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
  555. ret = EFI_INVALID_PARAMETER;
  556. goto out;
  557. }
  558. /* Trim output buffer size */
  559. tmp_dsize = *data_size;
  560. if (name_size + tmp_dsize >
  561. max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
  562. tmp_dsize = max_payload_size -
  563. MM_VARIABLE_ACCESS_HEADER_SIZE -
  564. name_size;
  565. }
  566. /* Get communication buffer and initialize header */
  567. payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize;
  568. comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
  569. SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret);
  570. if (!comm_buf)
  571. goto out;
  572. /* Fill in contents */
  573. guidcpy(&var_acc->guid, vendor);
  574. var_acc->data_size = tmp_dsize;
  575. var_acc->name_size = name_size;
  576. var_acc->attr = attributes ? *attributes : 0;
  577. memcpy(var_acc->name, variable_name, name_size);
  578. /* Communicate */
  579. ret = mm_communicate(comm_buf, payload_size);
  580. if (ret != EFI_SUCCESS && ret != EFI_BUFFER_TOO_SMALL)
  581. goto out;
  582. /* Update with reported data size for trimmed case */
  583. *data_size = var_acc->data_size;
  584. /*
  585. * UEFI > 2.7 needs the attributes set even if the buffer is
  586. * smaller
  587. */
  588. if (attributes) {
  589. tmp = get_property_int(variable_name, name_size, vendor,
  590. &var_property);
  591. if (tmp != EFI_SUCCESS) {
  592. ret = tmp;
  593. goto out;
  594. }
  595. *attributes = var_acc->attr;
  596. if (var_property.property &
  597. VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
  598. *attributes |= EFI_VARIABLE_READ_ONLY;
  599. }
  600. /* return if ret is EFI_BUFFER_TOO_SMALL */
  601. if (ret != EFI_SUCCESS)
  602. goto out;
  603. if (data)
  604. memcpy(data, (u8 *)var_acc->name + var_acc->name_size,
  605. var_acc->data_size);
  606. else
  607. ret = EFI_INVALID_PARAMETER;
  608. out:
  609. free(comm_buf);
  610. return ret;
  611. }
  612. efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
  613. u16 *variable_name,
  614. efi_guid_t *guid)
  615. {
  616. struct smm_variable_getnext *var_getnext;
  617. efi_uintn_t payload_size;
  618. efi_uintn_t out_name_size;
  619. efi_uintn_t in_name_size;
  620. u8 *comm_buf = NULL;
  621. efi_status_t ret;
  622. if (!variable_name_size || !variable_name || !guid) {
  623. ret = EFI_INVALID_PARAMETER;
  624. goto out;
  625. }
  626. out_name_size = *variable_name_size;
  627. in_name_size = u16_strsize(variable_name);
  628. if (out_name_size < in_name_size) {
  629. ret = EFI_INVALID_PARAMETER;
  630. goto out;
  631. }
  632. if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) {
  633. ret = EFI_INVALID_PARAMETER;
  634. goto out;
  635. }
  636. /* Trim output buffer size */
  637. if (out_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE)
  638. out_name_size = max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE;
  639. payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size;
  640. comm_buf = setup_mm_hdr((void **)&var_getnext, payload_size,
  641. SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME,
  642. &ret);
  643. if (!comm_buf)
  644. goto out;
  645. /* Fill in contents */
  646. guidcpy(&var_getnext->guid, guid);
  647. var_getnext->name_size = out_name_size;
  648. memcpy(var_getnext->name, variable_name, in_name_size);
  649. memset((u8 *)var_getnext->name + in_name_size, 0x0,
  650. out_name_size - in_name_size);
  651. /* Communicate */
  652. ret = mm_communicate(comm_buf, payload_size);
  653. if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
  654. /* Update with reported data size for trimmed case */
  655. *variable_name_size = var_getnext->name_size;
  656. }
  657. if (ret != EFI_SUCCESS)
  658. goto out;
  659. guidcpy(guid, &var_getnext->guid);
  660. memcpy(variable_name, var_getnext->name, var_getnext->name_size);
  661. out:
  662. free(comm_buf);
  663. return ret;
  664. }
  665. efi_status_t efi_set_variable_int(const u16 *variable_name,
  666. const efi_guid_t *vendor, u32 attributes,
  667. efi_uintn_t data_size, const void *data,
  668. bool ro_check)
  669. {
  670. efi_status_t ret, alt_ret = EFI_SUCCESS;
  671. struct var_check_property var_property;
  672. struct smm_variable_access *var_acc;
  673. efi_uintn_t payload_size;
  674. efi_uintn_t name_size;
  675. u8 *comm_buf = NULL;
  676. bool ro;
  677. if (!variable_name || variable_name[0] == 0 || !vendor) {
  678. ret = EFI_INVALID_PARAMETER;
  679. goto out;
  680. }
  681. if (data_size > 0 && !data) {
  682. ret = EFI_INVALID_PARAMETER;
  683. goto out;
  684. }
  685. /* Check payload size */
  686. name_size = u16_strsize(variable_name);
  687. payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
  688. if (payload_size > max_payload_size) {
  689. ret = EFI_INVALID_PARAMETER;
  690. goto out;
  691. }
  692. /*
  693. * Allocate the buffer early, before switching to RW (if needed)
  694. * so we won't need to account for any failures in reading/setting
  695. * the properties, if the allocation fails
  696. */
  697. comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
  698. SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
  699. if (!comm_buf)
  700. goto out;
  701. ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
  702. attributes &= EFI_VARIABLE_MASK;
  703. /*
  704. * The API has the ability to override RO flags. If no RO check was
  705. * requested switch the variable to RW for the duration of this call
  706. */
  707. ret = get_property_int(variable_name, name_size, vendor,
  708. &var_property);
  709. if (ret != EFI_SUCCESS)
  710. goto out;
  711. if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) {
  712. /* Bypass r/o check */
  713. if (!ro_check) {
  714. var_property.property &= ~VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
  715. ret = set_property_int(variable_name, name_size, vendor, &var_property);
  716. if (ret != EFI_SUCCESS)
  717. goto out;
  718. } else {
  719. ret = EFI_WRITE_PROTECTED;
  720. goto out;
  721. }
  722. }
  723. /* Fill in contents */
  724. guidcpy(&var_acc->guid, vendor);
  725. var_acc->data_size = data_size;
  726. var_acc->name_size = name_size;
  727. var_acc->attr = attributes;
  728. memcpy(var_acc->name, variable_name, name_size);
  729. memcpy((u8 *)var_acc->name + name_size, data, data_size);
  730. /* Communicate */
  731. ret = mm_communicate(comm_buf, payload_size);
  732. if (ret != EFI_SUCCESS)
  733. alt_ret = ret;
  734. if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) {
  735. var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
  736. var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
  737. var_property.attributes = attributes;
  738. var_property.minsize = 1;
  739. var_property.maxsize = var_acc->data_size;
  740. ret = set_property_int(variable_name, name_size, vendor, &var_property);
  741. }
  742. if (alt_ret != EFI_SUCCESS)
  743. goto out;
  744. if (!u16_strcmp(variable_name, u"PK"))
  745. alt_ret = efi_init_secure_state();
  746. out:
  747. free(comm_buf);
  748. return alt_ret == EFI_SUCCESS ? ret : alt_ret;
  749. }
  750. efi_status_t efi_query_variable_info_int(u32 attributes,
  751. u64 *max_variable_storage_size,
  752. u64 *remain_variable_storage_size,
  753. u64 *max_variable_size)
  754. {
  755. struct smm_variable_query_info *mm_query_info;
  756. efi_uintn_t payload_size;
  757. efi_status_t ret;
  758. u8 *comm_buf;
  759. payload_size = sizeof(*mm_query_info);
  760. comm_buf = setup_mm_hdr((void **)&mm_query_info, payload_size,
  761. SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO,
  762. &ret);
  763. if (!comm_buf)
  764. goto out;
  765. mm_query_info->attr = attributes;
  766. ret = mm_communicate(comm_buf, payload_size);
  767. if (ret != EFI_SUCCESS)
  768. goto out;
  769. *max_variable_storage_size = mm_query_info->max_variable_storage;
  770. *remain_variable_storage_size =
  771. mm_query_info->remaining_variable_storage;
  772. *max_variable_size = mm_query_info->max_variable_size;
  773. out:
  774. free(comm_buf);
  775. return ret;
  776. }
  777. /**
  778. * efi_query_variable_info() - get information about EFI variables
  779. *
  780. * This function implements the QueryVariableInfo() runtime service.
  781. *
  782. * See the Unified Extensible Firmware Interface (UEFI) specification for
  783. * details.
  784. *
  785. * @attributes: bitmask to select variables to be
  786. * queried
  787. * @maximum_variable_storage_size: maximum size of storage area for the
  788. * selected variable types
  789. * @remaining_variable_storage_size: remaining size of storage are for the
  790. * selected variable types
  791. * @maximum_variable_size: maximum size of a variable of the
  792. * selected type
  793. * Return: status code
  794. */
  795. efi_status_t EFIAPI __efi_runtime
  796. efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
  797. u64 *remain_variable_storage_size,
  798. u64 *max_variable_size)
  799. {
  800. return EFI_UNSUPPORTED;
  801. }
  802. /**
  803. * efi_set_variable_runtime() - runtime implementation of SetVariable()
  804. *
  805. * @variable_name: name of the variable
  806. * @guid: vendor GUID
  807. * @attributes: attributes of the variable
  808. * @data_size: size of the buffer with the variable value
  809. * @data: buffer with the variable value
  810. * Return: status code
  811. */
  812. static efi_status_t __efi_runtime EFIAPI
  813. efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
  814. u32 attributes, efi_uintn_t data_size,
  815. const void *data)
  816. {
  817. return EFI_UNSUPPORTED;
  818. }
  819. /**
  820. * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
  821. */
  822. void efi_variables_boot_exit_notify(void)
  823. {
  824. efi_status_t ret;
  825. u8 *comm_buf;
  826. loff_t len;
  827. struct efi_var_file *var_buf;
  828. comm_buf = setup_mm_hdr(NULL, 0,
  829. SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, &ret);
  830. if (comm_buf)
  831. ret = mm_communicate(comm_buf, 0);
  832. else
  833. ret = EFI_NOT_FOUND;
  834. if (ret != EFI_SUCCESS)
  835. log_err("Unable to notify the MM partition for ExitBootServices\n");
  836. free(comm_buf);
  837. /*
  838. * Populate the list for runtime variables.
  839. * asking EFI_VARIABLE_RUNTIME_ACCESS is redundant, since
  840. * efi_var_mem_notify_exit_boot_services will clean those, but that's fine
  841. */
  842. ret = efi_var_collect(&var_buf, &len, EFI_VARIABLE_RUNTIME_ACCESS);
  843. if (ret != EFI_SUCCESS)
  844. log_err("Can't populate EFI variables. No runtime variables will be available\n");
  845. else
  846. efi_var_buf_update(var_buf);
  847. free(var_buf);
  848. /* Update runtime service table */
  849. efi_runtime_services.query_variable_info =
  850. efi_query_variable_info_runtime;
  851. efi_runtime_services.get_variable = efi_get_variable_runtime;
  852. efi_runtime_services.get_next_variable_name =
  853. efi_get_next_variable_name_runtime;
  854. efi_runtime_services.set_variable = efi_set_variable_runtime;
  855. efi_update_table_header_crc32(&efi_runtime_services.hdr);
  856. }
  857. /**
  858. * efi_init_variables() - initialize variable services
  859. *
  860. * Return: status code
  861. */
  862. efi_status_t efi_init_variables(void)
  863. {
  864. efi_status_t ret;
  865. /* Create a cached copy of the variables that will be enabled on ExitBootServices() */
  866. ret = efi_var_mem_init();
  867. if (ret != EFI_SUCCESS)
  868. return ret;
  869. ret = get_max_payload(&max_payload_size);
  870. if (ret != EFI_SUCCESS)
  871. return ret;
  872. max_buffer_size = MM_COMMUNICATE_HEADER_SIZE +
  873. MM_VARIABLE_COMMUNICATE_SIZE +
  874. max_payload_size;
  875. ret = efi_init_secure_state();
  876. if (ret != EFI_SUCCESS)
  877. return ret;
  878. return EFI_SUCCESS;
  879. }