qcom_qseecom_uefisecapp.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Client driver for Qualcomm UEFI Secure Application (qcom.tz.uefisecapp).
  4. * Provides access to UEFI variables on platforms where they are secured by the
  5. * aforementioned Secure Execution Environment (SEE) application.
  6. *
  7. * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
  8. */
  9. #include <linux/efi.h>
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/mutex.h>
  13. #include <linux/of.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/sizes.h>
  16. #include <linux/slab.h>
  17. #include <linux/types.h>
  18. #include <linux/ucs2_string.h>
  19. #include <linux/firmware/qcom/qcom_qseecom.h>
  20. #include <linux/firmware/qcom/qcom_scm.h>
  21. #include <linux/firmware/qcom/qcom_tzmem.h>
  22. /* -- Qualcomm "uefisecapp" interface definitions. -------------------------- */
  23. /* Maximum length of name string with null-terminator */
  24. #define QSEE_MAX_NAME_LEN 1024
  25. #define QSEE_CMD_UEFI(x) (0x8000 | (x))
  26. #define QSEE_CMD_UEFI_GET_VARIABLE QSEE_CMD_UEFI(0)
  27. #define QSEE_CMD_UEFI_SET_VARIABLE QSEE_CMD_UEFI(1)
  28. #define QSEE_CMD_UEFI_GET_NEXT_VARIABLE QSEE_CMD_UEFI(2)
  29. #define QSEE_CMD_UEFI_QUERY_VARIABLE_INFO QSEE_CMD_UEFI(3)
  30. /**
  31. * struct qsee_req_uefi_get_variable - Request for GetVariable command.
  32. * @command_id: The ID of the command. Must be %QSEE_CMD_UEFI_GET_VARIABLE.
  33. * @length: Length of the request in bytes, including this struct and any
  34. * parameters (name, GUID) stored after it as well as any padding
  35. * thereof for alignment.
  36. * @name_offset: Offset from the start of this struct to where the variable
  37. * name is stored (as utf-16 string), in bytes.
  38. * @name_size: Size of the name parameter in bytes, including null-terminator.
  39. * @guid_offset: Offset from the start of this struct to where the GUID
  40. * parameter is stored, in bytes.
  41. * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
  42. * @data_size: Size of the output buffer, in bytes.
  43. */
  44. struct qsee_req_uefi_get_variable {
  45. u32 command_id;
  46. u32 length;
  47. u32 name_offset;
  48. u32 name_size;
  49. u32 guid_offset;
  50. u32 guid_size;
  51. u32 data_size;
  52. } __packed;
  53. /**
  54. * struct qsee_rsp_uefi_get_variable - Response for GetVariable command.
  55. * @command_id: The ID of the command. Should be %QSEE_CMD_UEFI_GET_VARIABLE.
  56. * @length: Length of the response in bytes, including this struct and the
  57. * returned data.
  58. * @status: Status of this command.
  59. * @attributes: EFI variable attributes.
  60. * @data_offset: Offset from the start of this struct to where the data is
  61. * stored, in bytes.
  62. * @data_size: Size of the returned data, in bytes. In case status indicates
  63. * that the buffer is too small, this will be the size required
  64. * to store the EFI variable data.
  65. */
  66. struct qsee_rsp_uefi_get_variable {
  67. u32 command_id;
  68. u32 length;
  69. u32 status;
  70. u32 attributes;
  71. u32 data_offset;
  72. u32 data_size;
  73. } __packed;
  74. /**
  75. * struct qsee_req_uefi_set_variable - Request for the SetVariable command.
  76. * @command_id: The ID of the command. Must be %QSEE_CMD_UEFI_SET_VARIABLE.
  77. * @length: Length of the request in bytes, including this struct and any
  78. * parameters (name, GUID, data) stored after it as well as any
  79. * padding thereof required for alignment.
  80. * @name_offset: Offset from the start of this struct to where the variable
  81. * name is stored (as utf-16 string), in bytes.
  82. * @name_size: Size of the name parameter in bytes, including null-terminator.
  83. * @guid_offset: Offset from the start of this struct to where the GUID
  84. * parameter is stored, in bytes.
  85. * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
  86. * @attributes: The EFI variable attributes to set for this variable.
  87. * @data_offset: Offset from the start of this struct to where the EFI variable
  88. * data is stored, in bytes.
  89. * @data_size: Size of EFI variable data, in bytes.
  90. *
  91. */
  92. struct qsee_req_uefi_set_variable {
  93. u32 command_id;
  94. u32 length;
  95. u32 name_offset;
  96. u32 name_size;
  97. u32 guid_offset;
  98. u32 guid_size;
  99. u32 attributes;
  100. u32 data_offset;
  101. u32 data_size;
  102. } __packed;
  103. /**
  104. * struct qsee_rsp_uefi_set_variable - Response for the SetVariable command.
  105. * @command_id: The ID of the command. Should be %QSEE_CMD_UEFI_SET_VARIABLE.
  106. * @length: The length of this response, i.e. the size of this struct in
  107. * bytes.
  108. * @status: Status of this command.
  109. * @_unknown1: Unknown response field.
  110. * @_unknown2: Unknown response field.
  111. */
  112. struct qsee_rsp_uefi_set_variable {
  113. u32 command_id;
  114. u32 length;
  115. u32 status;
  116. u32 _unknown1;
  117. u32 _unknown2;
  118. } __packed;
  119. /**
  120. * struct qsee_req_uefi_get_next_variable - Request for the
  121. * GetNextVariableName command.
  122. * @command_id: The ID of the command. Must be
  123. * %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
  124. * @length: Length of the request in bytes, including this struct and any
  125. * parameters (name, GUID) stored after it as well as any padding
  126. * thereof for alignment.
  127. * @guid_offset: Offset from the start of this struct to where the GUID
  128. * parameter is stored, in bytes.
  129. * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
  130. * @name_offset: Offset from the start of this struct to where the variable
  131. * name is stored (as utf-16 string), in bytes.
  132. * @name_size: Size of the name parameter in bytes, including null-terminator.
  133. */
  134. struct qsee_req_uefi_get_next_variable {
  135. u32 command_id;
  136. u32 length;
  137. u32 guid_offset;
  138. u32 guid_size;
  139. u32 name_offset;
  140. u32 name_size;
  141. } __packed;
  142. /**
  143. * struct qsee_rsp_uefi_get_next_variable - Response for the
  144. * GetNextVariableName command.
  145. * @command_id: The ID of the command. Should be
  146. * %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
  147. * @length: Length of the response in bytes, including this struct and any
  148. * parameters (name, GUID) stored after it as well as any padding
  149. * thereof for alignment.
  150. * @status: Status of this command.
  151. * @guid_offset: Offset from the start of this struct to where the GUID
  152. * parameter is stored, in bytes.
  153. * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
  154. * @name_offset: Offset from the start of this struct to where the variable
  155. * name is stored (as utf-16 string), in bytes.
  156. * @name_size: Size of the name parameter in bytes, including null-terminator.
  157. */
  158. struct qsee_rsp_uefi_get_next_variable {
  159. u32 command_id;
  160. u32 length;
  161. u32 status;
  162. u32 guid_offset;
  163. u32 guid_size;
  164. u32 name_offset;
  165. u32 name_size;
  166. } __packed;
  167. /**
  168. * struct qsee_req_uefi_query_variable_info - Response for the
  169. * GetNextVariableName command.
  170. * @command_id: The ID of the command. Must be
  171. * %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
  172. * @length: The length of this request, i.e. the size of this struct in
  173. * bytes.
  174. * @attributes: The storage attributes to query the info for.
  175. */
  176. struct qsee_req_uefi_query_variable_info {
  177. u32 command_id;
  178. u32 length;
  179. u32 attributes;
  180. } __packed;
  181. /**
  182. * struct qsee_rsp_uefi_query_variable_info - Response for the
  183. * GetNextVariableName command.
  184. * @command_id: The ID of the command. Must be
  185. * %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
  186. * @length: The length of this response, i.e. the size of this
  187. * struct in bytes.
  188. * @status: Status of this command.
  189. * @_pad: Padding.
  190. * @storage_space: Full storage space size, in bytes.
  191. * @remaining_space: Free storage space available, in bytes.
  192. * @max_variable_size: Maximum variable data size, in bytes.
  193. */
  194. struct qsee_rsp_uefi_query_variable_info {
  195. u32 command_id;
  196. u32 length;
  197. u32 status;
  198. u32 _pad;
  199. u64 storage_space;
  200. u64 remaining_space;
  201. u64 max_variable_size;
  202. } __packed;
  203. /* -- Alignment helpers ----------------------------------------------------- */
  204. /*
  205. * Helper macro to ensure proper alignment of types (fields and arrays) when
  206. * stored in some (contiguous) buffer.
  207. *
  208. * Note: The driver from which this one has been reverse-engineered expects an
  209. * alignment of 8 bytes (64 bits) for GUIDs. Our definition of efi_guid_t,
  210. * however, has an alignment of 4 byte (32 bits). So far, this seems to work
  211. * fine here. See also the comment on the typedef of efi_guid_t.
  212. *
  213. * Note: It looks like uefisecapp is quite picky about how the memory passed to
  214. * it is structured and aligned. In particular the request/response setup used
  215. * for QSEE_CMD_UEFI_GET_VARIABLE. While qcom_qseecom_app_send(), in theory,
  216. * accepts separate buffers/addresses for the request and response parts, in
  217. * practice, however, it seems to expect them to be both part of a larger
  218. * contiguous block. We initially allocated separate buffers for the request
  219. * and response but this caused the QSEE_CMD_UEFI_GET_VARIABLE command to
  220. * either not write any response to the response buffer or outright crash the
  221. * device. Therefore, we now allocate a single contiguous block of DMA memory
  222. * for both and properly align the data using the macros below. In particular,
  223. * request and response structs are aligned at 8 byte (via __reqdata_offs()),
  224. * following the driver that this has been reverse-engineered from.
  225. */
  226. #define qcuefi_buf_align_fields(fields...) \
  227. ({ \
  228. size_t __len = 0; \
  229. fields \
  230. __len; \
  231. })
  232. #define __field_impl(size, align, offset) \
  233. ({ \
  234. size_t *__offset = (offset); \
  235. size_t __aligned; \
  236. \
  237. __aligned = ALIGN(__len, align); \
  238. __len = __aligned + (size); \
  239. \
  240. if (__offset) \
  241. *__offset = __aligned; \
  242. });
  243. #define __array_offs(type, count, offset) \
  244. __field_impl(sizeof(type) * (count), __alignof__(type), offset)
  245. #define __array_offs_aligned(type, count, align, offset) \
  246. __field_impl(sizeof(type) * (count), align, offset)
  247. #define __reqdata_offs(size, offset) \
  248. __array_offs_aligned(u8, size, 8, offset)
  249. #define __array(type, count) __array_offs(type, count, NULL)
  250. #define __field_offs(type, offset) __array_offs(type, 1, offset)
  251. #define __field(type) __array_offs(type, 1, NULL)
  252. /* -- UEFI app interface. --------------------------------------------------- */
  253. struct qcuefi_client {
  254. struct qseecom_client *client;
  255. struct efivars efivars;
  256. struct qcom_tzmem_pool *mempool;
  257. };
  258. static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
  259. {
  260. return &qcuefi->client->aux_dev.dev;
  261. }
  262. static efi_status_t qsee_uefi_status_to_efi(u32 status)
  263. {
  264. u64 category = status & 0xf0000000;
  265. u64 code = status & 0x0fffffff;
  266. return category << (BITS_PER_LONG - 32) | code;
  267. }
  268. static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
  269. const efi_guid_t *guid, u32 *attributes,
  270. unsigned long *data_size, void *data)
  271. {
  272. struct qsee_req_uefi_get_variable *req_data;
  273. struct qsee_rsp_uefi_get_variable *rsp_data;
  274. void *cmd_buf __free(qcom_tzmem) = NULL;
  275. unsigned long buffer_size = *data_size;
  276. unsigned long name_length;
  277. efi_status_t efi_status;
  278. size_t cmd_buf_size;
  279. size_t guid_offs;
  280. size_t name_offs;
  281. size_t req_size;
  282. size_t rsp_size;
  283. size_t req_offs;
  284. size_t rsp_offs;
  285. ssize_t status;
  286. if (!name || !guid)
  287. return EFI_INVALID_PARAMETER;
  288. name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
  289. if (name_length > QSEE_MAX_NAME_LEN)
  290. return EFI_INVALID_PARAMETER;
  291. if (buffer_size && !data)
  292. return EFI_INVALID_PARAMETER;
  293. req_size = qcuefi_buf_align_fields(
  294. __field(*req_data)
  295. __array_offs(*name, name_length, &name_offs)
  296. __field_offs(*guid, &guid_offs)
  297. );
  298. rsp_size = qcuefi_buf_align_fields(
  299. __field(*rsp_data)
  300. __array(u8, buffer_size)
  301. );
  302. cmd_buf_size = qcuefi_buf_align_fields(
  303. __reqdata_offs(req_size, &req_offs)
  304. __reqdata_offs(rsp_size, &rsp_offs)
  305. );
  306. cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
  307. if (!cmd_buf)
  308. return EFI_OUT_OF_RESOURCES;
  309. req_data = cmd_buf + req_offs;
  310. rsp_data = cmd_buf + rsp_offs;
  311. req_data->command_id = QSEE_CMD_UEFI_GET_VARIABLE;
  312. req_data->data_size = buffer_size;
  313. req_data->name_offset = name_offs;
  314. req_data->name_size = name_length * sizeof(*name);
  315. req_data->guid_offset = guid_offs;
  316. req_data->guid_size = sizeof(*guid);
  317. req_data->length = req_size;
  318. status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
  319. if (status < 0)
  320. return EFI_INVALID_PARAMETER;
  321. memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
  322. status = qcom_qseecom_app_send(qcuefi->client,
  323. cmd_buf + req_offs, req_size,
  324. cmd_buf + rsp_offs, rsp_size);
  325. if (status)
  326. return EFI_DEVICE_ERROR;
  327. if (rsp_data->command_id != QSEE_CMD_UEFI_GET_VARIABLE)
  328. return EFI_DEVICE_ERROR;
  329. if (rsp_data->length < sizeof(*rsp_data))
  330. return EFI_DEVICE_ERROR;
  331. if (rsp_data->status) {
  332. dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
  333. __func__, rsp_data->status);
  334. efi_status = qsee_uefi_status_to_efi(rsp_data->status);
  335. /* Update size and attributes in case buffer is too small. */
  336. if (efi_status == EFI_BUFFER_TOO_SMALL) {
  337. *data_size = rsp_data->data_size;
  338. if (attributes)
  339. *attributes = rsp_data->attributes;
  340. }
  341. return qsee_uefi_status_to_efi(rsp_data->status);
  342. }
  343. if (rsp_data->length > rsp_size)
  344. return EFI_DEVICE_ERROR;
  345. if (rsp_data->data_offset + rsp_data->data_size > rsp_data->length)
  346. return EFI_DEVICE_ERROR;
  347. /*
  348. * Note: We need to set attributes and data size even if the buffer is
  349. * too small and we won't copy any data. This is described in spec, so
  350. * that callers can either allocate a buffer properly (with two calls
  351. * to this function) or just read back attributes withouth having to
  352. * deal with that.
  353. *
  354. * Specifically:
  355. * - If we have a buffer size of zero and no buffer, just return the
  356. * attributes, required size, and indicate success.
  357. * - If the buffer size is nonzero but too small, indicate that as an
  358. * error.
  359. * - Otherwise, we are good to copy the data.
  360. *
  361. * Note that we have already ensured above that the buffer pointer is
  362. * non-NULL if its size is nonzero.
  363. */
  364. *data_size = rsp_data->data_size;
  365. if (attributes)
  366. *attributes = rsp_data->attributes;
  367. if (buffer_size == 0 && !data)
  368. return EFI_SUCCESS;
  369. if (buffer_size < rsp_data->data_size)
  370. return EFI_BUFFER_TOO_SMALL;
  371. memcpy(data, ((void *)rsp_data) + rsp_data->data_offset, rsp_data->data_size);
  372. return EFI_SUCCESS;
  373. }
  374. static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
  375. const efi_guid_t *guid, u32 attributes,
  376. unsigned long data_size, const void *data)
  377. {
  378. struct qsee_req_uefi_set_variable *req_data;
  379. struct qsee_rsp_uefi_set_variable *rsp_data;
  380. void *cmd_buf __free(qcom_tzmem) = NULL;
  381. unsigned long name_length;
  382. size_t cmd_buf_size;
  383. size_t name_offs;
  384. size_t guid_offs;
  385. size_t data_offs;
  386. size_t req_size;
  387. size_t req_offs;
  388. size_t rsp_offs;
  389. ssize_t status;
  390. if (!name || !guid)
  391. return EFI_INVALID_PARAMETER;
  392. name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
  393. if (name_length > QSEE_MAX_NAME_LEN)
  394. return EFI_INVALID_PARAMETER;
  395. /*
  396. * Make sure we have some data if data_size is nonzero. Note that using
  397. * a size of zero is a valid use-case described in spec and deletes the
  398. * variable.
  399. */
  400. if (data_size && !data)
  401. return EFI_INVALID_PARAMETER;
  402. req_size = qcuefi_buf_align_fields(
  403. __field(*req_data)
  404. __array_offs(*name, name_length, &name_offs)
  405. __field_offs(*guid, &guid_offs)
  406. __array_offs(u8, data_size, &data_offs)
  407. );
  408. cmd_buf_size = qcuefi_buf_align_fields(
  409. __reqdata_offs(req_size, &req_offs)
  410. __reqdata_offs(sizeof(*rsp_data), &rsp_offs)
  411. );
  412. cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
  413. if (!cmd_buf)
  414. return EFI_OUT_OF_RESOURCES;
  415. req_data = cmd_buf + req_offs;
  416. rsp_data = cmd_buf + rsp_offs;
  417. req_data->command_id = QSEE_CMD_UEFI_SET_VARIABLE;
  418. req_data->attributes = attributes;
  419. req_data->name_offset = name_offs;
  420. req_data->name_size = name_length * sizeof(*name);
  421. req_data->guid_offset = guid_offs;
  422. req_data->guid_size = sizeof(*guid);
  423. req_data->data_offset = data_offs;
  424. req_data->data_size = data_size;
  425. req_data->length = req_size;
  426. status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
  427. if (status < 0)
  428. return EFI_INVALID_PARAMETER;
  429. memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
  430. if (data_size)
  431. memcpy(((void *)req_data) + req_data->data_offset, data, req_data->data_size);
  432. status = qcom_qseecom_app_send(qcuefi->client,
  433. cmd_buf + req_offs, req_size,
  434. cmd_buf + rsp_offs, sizeof(*rsp_data));
  435. if (status)
  436. return EFI_DEVICE_ERROR;
  437. if (rsp_data->command_id != QSEE_CMD_UEFI_SET_VARIABLE)
  438. return EFI_DEVICE_ERROR;
  439. if (rsp_data->length != sizeof(*rsp_data))
  440. return EFI_DEVICE_ERROR;
  441. if (rsp_data->status) {
  442. dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
  443. __func__, rsp_data->status);
  444. return qsee_uefi_status_to_efi(rsp_data->status);
  445. }
  446. return EFI_SUCCESS;
  447. }
  448. static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
  449. unsigned long *name_size, efi_char16_t *name,
  450. efi_guid_t *guid)
  451. {
  452. struct qsee_req_uefi_get_next_variable *req_data;
  453. struct qsee_rsp_uefi_get_next_variable *rsp_data;
  454. void *cmd_buf __free(qcom_tzmem) = NULL;
  455. efi_status_t efi_status;
  456. size_t cmd_buf_size;
  457. size_t guid_offs;
  458. size_t name_offs;
  459. size_t req_size;
  460. size_t rsp_size;
  461. size_t req_offs;
  462. size_t rsp_offs;
  463. ssize_t status;
  464. if (!name_size || !name || !guid)
  465. return EFI_INVALID_PARAMETER;
  466. if (*name_size == 0)
  467. return EFI_INVALID_PARAMETER;
  468. req_size = qcuefi_buf_align_fields(
  469. __field(*req_data)
  470. __field_offs(*guid, &guid_offs)
  471. __array_offs(*name, *name_size / sizeof(*name), &name_offs)
  472. );
  473. rsp_size = qcuefi_buf_align_fields(
  474. __field(*rsp_data)
  475. __field(*guid)
  476. __array(*name, *name_size / sizeof(*name))
  477. );
  478. cmd_buf_size = qcuefi_buf_align_fields(
  479. __reqdata_offs(req_size, &req_offs)
  480. __reqdata_offs(rsp_size, &rsp_offs)
  481. );
  482. cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
  483. if (!cmd_buf)
  484. return EFI_OUT_OF_RESOURCES;
  485. req_data = cmd_buf + req_offs;
  486. rsp_data = cmd_buf + rsp_offs;
  487. req_data->command_id = QSEE_CMD_UEFI_GET_NEXT_VARIABLE;
  488. req_data->guid_offset = guid_offs;
  489. req_data->guid_size = sizeof(*guid);
  490. req_data->name_offset = name_offs;
  491. req_data->name_size = *name_size;
  492. req_data->length = req_size;
  493. memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
  494. status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name,
  495. *name_size / sizeof(*name));
  496. if (status < 0)
  497. return EFI_INVALID_PARAMETER;
  498. status = qcom_qseecom_app_send(qcuefi->client,
  499. cmd_buf + req_offs, req_size,
  500. cmd_buf + rsp_offs, rsp_size);
  501. if (status)
  502. return EFI_DEVICE_ERROR;
  503. if (rsp_data->command_id != QSEE_CMD_UEFI_GET_NEXT_VARIABLE)
  504. return EFI_DEVICE_ERROR;
  505. if (rsp_data->length < sizeof(*rsp_data))
  506. return EFI_DEVICE_ERROR;
  507. if (rsp_data->status) {
  508. dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
  509. __func__, rsp_data->status);
  510. efi_status = qsee_uefi_status_to_efi(rsp_data->status);
  511. /*
  512. * If the buffer to hold the name is too small, update the
  513. * name_size with the required size, so that callers can
  514. * reallocate it accordingly.
  515. */
  516. if (efi_status == EFI_BUFFER_TOO_SMALL)
  517. *name_size = rsp_data->name_size;
  518. return efi_status;
  519. }
  520. if (rsp_data->length > rsp_size)
  521. return EFI_DEVICE_ERROR;
  522. if (rsp_data->name_offset + rsp_data->name_size > rsp_data->length)
  523. return EFI_DEVICE_ERROR;
  524. if (rsp_data->guid_offset + rsp_data->guid_size > rsp_data->length)
  525. return EFI_DEVICE_ERROR;
  526. if (rsp_data->name_size > *name_size) {
  527. *name_size = rsp_data->name_size;
  528. return EFI_BUFFER_TOO_SMALL;
  529. }
  530. if (rsp_data->guid_size != sizeof(*guid))
  531. return EFI_DEVICE_ERROR;
  532. memcpy(guid, ((void *)rsp_data) + rsp_data->guid_offset, rsp_data->guid_size);
  533. status = ucs2_strscpy(name, ((void *)rsp_data) + rsp_data->name_offset,
  534. rsp_data->name_size / sizeof(*name));
  535. *name_size = rsp_data->name_size;
  536. if (status < 0)
  537. /*
  538. * Return EFI_DEVICE_ERROR here because the buffer size should
  539. * have already been validated above, causing this function to
  540. * bail with EFI_BUFFER_TOO_SMALL.
  541. */
  542. return EFI_DEVICE_ERROR;
  543. return EFI_SUCCESS;
  544. }
  545. static efi_status_t qsee_uefi_query_variable_info(struct qcuefi_client *qcuefi, u32 attr,
  546. u64 *storage_space, u64 *remaining_space,
  547. u64 *max_variable_size)
  548. {
  549. struct qsee_req_uefi_query_variable_info *req_data;
  550. struct qsee_rsp_uefi_query_variable_info *rsp_data;
  551. void *cmd_buf __free(qcom_tzmem) = NULL;
  552. size_t cmd_buf_size;
  553. size_t req_offs;
  554. size_t rsp_offs;
  555. int status;
  556. cmd_buf_size = qcuefi_buf_align_fields(
  557. __reqdata_offs(sizeof(*req_data), &req_offs)
  558. __reqdata_offs(sizeof(*rsp_data), &rsp_offs)
  559. );
  560. cmd_buf = qcom_tzmem_alloc(qcuefi->mempool, cmd_buf_size, GFP_KERNEL);
  561. if (!cmd_buf)
  562. return EFI_OUT_OF_RESOURCES;
  563. req_data = cmd_buf + req_offs;
  564. rsp_data = cmd_buf + rsp_offs;
  565. req_data->command_id = QSEE_CMD_UEFI_QUERY_VARIABLE_INFO;
  566. req_data->attributes = attr;
  567. req_data->length = sizeof(*req_data);
  568. status = qcom_qseecom_app_send(qcuefi->client,
  569. cmd_buf + req_offs, sizeof(*req_data),
  570. cmd_buf + rsp_offs, sizeof(*rsp_data));
  571. if (status)
  572. return EFI_DEVICE_ERROR;
  573. if (rsp_data->command_id != QSEE_CMD_UEFI_QUERY_VARIABLE_INFO)
  574. return EFI_DEVICE_ERROR;
  575. if (rsp_data->length != sizeof(*rsp_data))
  576. return EFI_DEVICE_ERROR;
  577. if (rsp_data->status) {
  578. dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
  579. __func__, rsp_data->status);
  580. return qsee_uefi_status_to_efi(rsp_data->status);
  581. }
  582. if (storage_space)
  583. *storage_space = rsp_data->storage_space;
  584. if (remaining_space)
  585. *remaining_space = rsp_data->remaining_space;
  586. if (max_variable_size)
  587. *max_variable_size = rsp_data->max_variable_size;
  588. return EFI_SUCCESS;
  589. }
  590. /* -- Global efivar interface. ---------------------------------------------- */
  591. static struct qcuefi_client *__qcuefi;
  592. static DEFINE_MUTEX(__qcuefi_lock);
  593. static int qcuefi_set_reference(struct qcuefi_client *qcuefi)
  594. {
  595. mutex_lock(&__qcuefi_lock);
  596. if (qcuefi && __qcuefi) {
  597. mutex_unlock(&__qcuefi_lock);
  598. return -EEXIST;
  599. }
  600. __qcuefi = qcuefi;
  601. mutex_unlock(&__qcuefi_lock);
  602. return 0;
  603. }
  604. static struct qcuefi_client *qcuefi_acquire(void)
  605. {
  606. mutex_lock(&__qcuefi_lock);
  607. if (!__qcuefi) {
  608. mutex_unlock(&__qcuefi_lock);
  609. return NULL;
  610. }
  611. return __qcuefi;
  612. }
  613. static void qcuefi_release(void)
  614. {
  615. mutex_unlock(&__qcuefi_lock);
  616. }
  617. static efi_status_t qcuefi_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
  618. unsigned long *data_size, void *data)
  619. {
  620. struct qcuefi_client *qcuefi;
  621. efi_status_t status;
  622. qcuefi = qcuefi_acquire();
  623. if (!qcuefi)
  624. return EFI_NOT_READY;
  625. status = qsee_uefi_get_variable(qcuefi, name, vendor, attr, data_size, data);
  626. qcuefi_release();
  627. return status;
  628. }
  629. static efi_status_t qcuefi_set_variable(efi_char16_t *name, efi_guid_t *vendor,
  630. u32 attr, unsigned long data_size, void *data)
  631. {
  632. struct qcuefi_client *qcuefi;
  633. efi_status_t status;
  634. qcuefi = qcuefi_acquire();
  635. if (!qcuefi)
  636. return EFI_NOT_READY;
  637. status = qsee_uefi_set_variable(qcuefi, name, vendor, attr, data_size, data);
  638. qcuefi_release();
  639. return status;
  640. }
  641. static efi_status_t qcuefi_get_next_variable(unsigned long *name_size, efi_char16_t *name,
  642. efi_guid_t *vendor)
  643. {
  644. struct qcuefi_client *qcuefi;
  645. efi_status_t status;
  646. qcuefi = qcuefi_acquire();
  647. if (!qcuefi)
  648. return EFI_NOT_READY;
  649. status = qsee_uefi_get_next_variable(qcuefi, name_size, name, vendor);
  650. qcuefi_release();
  651. return status;
  652. }
  653. static efi_status_t qcuefi_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space,
  654. u64 *max_variable_size)
  655. {
  656. struct qcuefi_client *qcuefi;
  657. efi_status_t status;
  658. qcuefi = qcuefi_acquire();
  659. if (!qcuefi)
  660. return EFI_NOT_READY;
  661. status = qsee_uefi_query_variable_info(qcuefi, attr, storage_space, remaining_space,
  662. max_variable_size);
  663. qcuefi_release();
  664. return status;
  665. }
  666. static const struct efivar_operations qcom_efivar_ops = {
  667. .get_variable = qcuefi_get_variable,
  668. .set_variable = qcuefi_set_variable,
  669. .get_next_variable = qcuefi_get_next_variable,
  670. .query_variable_info = qcuefi_query_variable_info,
  671. };
  672. /* -- Driver setup. --------------------------------------------------------- */
  673. static int qcom_uefisecapp_probe(struct auxiliary_device *aux_dev,
  674. const struct auxiliary_device_id *aux_dev_id)
  675. {
  676. struct qcom_tzmem_pool_config pool_config;
  677. struct qcuefi_client *qcuefi;
  678. int status;
  679. qcuefi = devm_kzalloc(&aux_dev->dev, sizeof(*qcuefi), GFP_KERNEL);
  680. if (!qcuefi)
  681. return -ENOMEM;
  682. qcuefi->client = container_of(aux_dev, struct qseecom_client, aux_dev);
  683. memset(&pool_config, 0, sizeof(pool_config));
  684. pool_config.initial_size = SZ_4K;
  685. pool_config.policy = QCOM_TZMEM_POLICY_MULTIPLIER;
  686. pool_config.increment = 2;
  687. pool_config.max_size = SZ_256K;
  688. qcuefi->mempool = devm_qcom_tzmem_pool_new(&aux_dev->dev, &pool_config);
  689. if (IS_ERR(qcuefi->mempool))
  690. return PTR_ERR(qcuefi->mempool);
  691. auxiliary_set_drvdata(aux_dev, qcuefi);
  692. status = qcuefi_set_reference(qcuefi);
  693. if (status)
  694. return status;
  695. status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops);
  696. if (status)
  697. qcuefi_set_reference(NULL);
  698. return status;
  699. }
  700. static void qcom_uefisecapp_remove(struct auxiliary_device *aux_dev)
  701. {
  702. struct qcuefi_client *qcuefi = auxiliary_get_drvdata(aux_dev);
  703. efivars_unregister(&qcuefi->efivars);
  704. qcuefi_set_reference(NULL);
  705. }
  706. static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = {
  707. { .name = "qcom_qseecom.uefisecapp" },
  708. {}
  709. };
  710. MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table);
  711. static struct auxiliary_driver qcom_uefisecapp_driver = {
  712. .probe = qcom_uefisecapp_probe,
  713. .remove = qcom_uefisecapp_remove,
  714. .id_table = qcom_uefisecapp_id_table,
  715. .driver = {
  716. .name = "qcom_qseecom_uefisecapp",
  717. .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  718. },
  719. };
  720. module_auxiliary_driver(qcom_uefisecapp_driver);
  721. MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  722. MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
  723. MODULE_LICENSE("GPL");