mei-amt-version.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /******************************************************************************
  2. * Intel Management Engine Interface (Intel MEI) Linux driver
  3. * Intel MEI Interface Header
  4. *
  5. * This file is provided under a dual BSD/GPLv2 license. When using or
  6. * redistributing this file, you may do so under either license.
  7. *
  8. * GPL LICENSE SUMMARY
  9. *
  10. * Copyright(c) 2012 Intel Corporation. All rights reserved.
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of version 2 of the GNU General Public License as
  14. * published by the Free Software Foundation.
  15. *
  16. * This program is distributed in the hope that it will be useful, but
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  24. * USA
  25. *
  26. * The full GNU General Public License is included in this distribution
  27. * in the file called LICENSE.GPL.
  28. *
  29. * Contact Information:
  30. * Intel Corporation.
  31. * linux-mei@linux.intel.com
  32. * http://www.intel.com
  33. *
  34. * BSD LICENSE
  35. *
  36. * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
  37. * All rights reserved.
  38. *
  39. * Redistribution and use in source and binary forms, with or without
  40. * modification, are permitted provided that the following conditions
  41. * are met:
  42. *
  43. * * Redistributions of source code must retain the above copyright
  44. * notice, this list of conditions and the following disclaimer.
  45. * * Redistributions in binary form must reproduce the above copyright
  46. * notice, this list of conditions and the following disclaimer in
  47. * the documentation and/or other materials provided with the
  48. * distribution.
  49. * * Neither the name Intel Corporation nor the names of its
  50. * contributors may be used to endorse or promote products derived
  51. * from this software without specific prior written permission.
  52. *
  53. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  54. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  55. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  56. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  57. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  58. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  59. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  60. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  61. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  62. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  63. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  64. *
  65. *****************************************************************************/
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <string.h>
  69. #include <fcntl.h>
  70. #include <sys/ioctl.h>
  71. #include <unistd.h>
  72. #include <errno.h>
  73. #include <stdint.h>
  74. #include <stdbool.h>
  75. #include <bits/wordsize.h>
  76. #include <linux/mei.h>
  77. /*****************************************************************************
  78. * Intel Management Engine Interface
  79. *****************************************************************************/
  80. #define mei_msg(_me, fmt, ARGS...) do { \
  81. if (_me->verbose) \
  82. fprintf(stderr, fmt, ##ARGS); \
  83. } while (0)
  84. #define mei_err(_me, fmt, ARGS...) do { \
  85. fprintf(stderr, "Error: " fmt, ##ARGS); \
  86. } while (0)
  87. struct mei {
  88. uuid_le guid;
  89. bool initialized;
  90. bool verbose;
  91. unsigned int buf_size;
  92. unsigned char prot_ver;
  93. int fd;
  94. };
  95. static void mei_deinit(struct mei *cl)
  96. {
  97. if (cl->fd != -1)
  98. close(cl->fd);
  99. cl->fd = -1;
  100. cl->buf_size = 0;
  101. cl->prot_ver = 0;
  102. cl->initialized = false;
  103. }
  104. static bool mei_init(struct mei *me, const uuid_le *guid,
  105. unsigned char req_protocol_version, bool verbose)
  106. {
  107. int result;
  108. struct mei_client *cl;
  109. struct mei_connect_client_data data;
  110. mei_deinit(me);
  111. me->verbose = verbose;
  112. me->fd = open("/dev/mei", O_RDWR);
  113. if (me->fd == -1) {
  114. mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
  115. goto err;
  116. }
  117. memcpy(&me->guid, guid, sizeof(*guid));
  118. memset(&data, 0, sizeof(data));
  119. me->initialized = true;
  120. memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
  121. result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
  122. if (result) {
  123. mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
  124. goto err;
  125. }
  126. cl = &data.out_client_properties;
  127. mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
  128. mei_msg(me, "protocol_version %d\n", cl->protocol_version);
  129. if ((req_protocol_version > 0) &&
  130. (cl->protocol_version != req_protocol_version)) {
  131. mei_err(me, "Intel MEI protocol version not supported\n");
  132. goto err;
  133. }
  134. me->buf_size = cl->max_msg_length;
  135. me->prot_ver = cl->protocol_version;
  136. return true;
  137. err:
  138. mei_deinit(me);
  139. return false;
  140. }
  141. static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
  142. ssize_t len, unsigned long timeout)
  143. {
  144. ssize_t rc;
  145. mei_msg(me, "call read length = %zd\n", len);
  146. rc = read(me->fd, buffer, len);
  147. if (rc < 0) {
  148. mei_err(me, "read failed with status %zd %s\n",
  149. rc, strerror(errno));
  150. mei_deinit(me);
  151. } else {
  152. mei_msg(me, "read succeeded with result %zd\n", rc);
  153. }
  154. return rc;
  155. }
  156. static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
  157. ssize_t len, unsigned long timeout)
  158. {
  159. struct timeval tv;
  160. ssize_t written;
  161. ssize_t rc;
  162. fd_set set;
  163. tv.tv_sec = timeout / 1000;
  164. tv.tv_usec = (timeout % 1000) * 1000000;
  165. mei_msg(me, "call write length = %zd\n", len);
  166. written = write(me->fd, buffer, len);
  167. if (written < 0) {
  168. rc = -errno;
  169. mei_err(me, "write failed with status %zd %s\n",
  170. written, strerror(errno));
  171. goto out;
  172. }
  173. FD_ZERO(&set);
  174. FD_SET(me->fd, &set);
  175. rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
  176. if (rc > 0 && FD_ISSET(me->fd, &set)) {
  177. mei_msg(me, "write success\n");
  178. } else if (rc == 0) {
  179. mei_err(me, "write failed on timeout with status\n");
  180. goto out;
  181. } else { /* rc < 0 */
  182. mei_err(me, "write failed on select with status %zd\n", rc);
  183. goto out;
  184. }
  185. rc = written;
  186. out:
  187. if (rc < 0)
  188. mei_deinit(me);
  189. return rc;
  190. }
  191. /***************************************************************************
  192. * Intel Advanced Management Technology ME Client
  193. ***************************************************************************/
  194. #define AMT_MAJOR_VERSION 1
  195. #define AMT_MINOR_VERSION 1
  196. #define AMT_STATUS_SUCCESS 0x0
  197. #define AMT_STATUS_INTERNAL_ERROR 0x1
  198. #define AMT_STATUS_NOT_READY 0x2
  199. #define AMT_STATUS_INVALID_AMT_MODE 0x3
  200. #define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
  201. #define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000
  202. #define AMT_STATUS_SDK_RESOURCES 0x1004
  203. #define AMT_BIOS_VERSION_LEN 65
  204. #define AMT_VERSIONS_NUMBER 50
  205. #define AMT_UNICODE_STRING_LEN 20
  206. struct amt_unicode_string {
  207. uint16_t length;
  208. char string[AMT_UNICODE_STRING_LEN];
  209. } __attribute__((packed));
  210. struct amt_version_type {
  211. struct amt_unicode_string description;
  212. struct amt_unicode_string version;
  213. } __attribute__((packed));
  214. struct amt_version {
  215. uint8_t major;
  216. uint8_t minor;
  217. } __attribute__((packed));
  218. struct amt_code_versions {
  219. uint8_t bios[AMT_BIOS_VERSION_LEN];
  220. uint32_t count;
  221. struct amt_version_type versions[AMT_VERSIONS_NUMBER];
  222. } __attribute__((packed));
  223. /***************************************************************************
  224. * Intel Advanced Management Technology Host Interface
  225. ***************************************************************************/
  226. struct amt_host_if_msg_header {
  227. struct amt_version version;
  228. uint16_t _reserved;
  229. uint32_t command;
  230. uint32_t length;
  231. } __attribute__((packed));
  232. struct amt_host_if_resp_header {
  233. struct amt_host_if_msg_header header;
  234. uint32_t status;
  235. unsigned char data[0];
  236. } __attribute__((packed));
  237. const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \
  238. 0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
  239. #define AMT_HOST_IF_CODE_VERSIONS_REQUEST 0x0400001A
  240. #define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
  241. const struct amt_host_if_msg_header CODE_VERSION_REQ = {
  242. .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
  243. ._reserved = 0,
  244. .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
  245. .length = 0
  246. };
  247. struct amt_host_if {
  248. struct mei mei_cl;
  249. unsigned long send_timeout;
  250. bool initialized;
  251. };
  252. static bool amt_host_if_init(struct amt_host_if *acmd,
  253. unsigned long send_timeout, bool verbose)
  254. {
  255. acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
  256. acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
  257. return acmd->initialized;
  258. }
  259. static void amt_host_if_deinit(struct amt_host_if *acmd)
  260. {
  261. mei_deinit(&acmd->mei_cl);
  262. acmd->initialized = false;
  263. }
  264. static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
  265. {
  266. uint32_t status = AMT_STATUS_SUCCESS;
  267. struct amt_code_versions *code_ver;
  268. size_t code_ver_len;
  269. uint32_t ver_type_cnt;
  270. uint32_t len;
  271. uint32_t i;
  272. code_ver = (struct amt_code_versions *)resp->data;
  273. /* length - sizeof(status) */
  274. code_ver_len = resp->header.length - sizeof(uint32_t);
  275. ver_type_cnt = code_ver_len -
  276. sizeof(code_ver->bios) -
  277. sizeof(code_ver->count);
  278. if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
  279. status = AMT_STATUS_INTERNAL_ERROR;
  280. goto out;
  281. }
  282. for (i = 0; i < code_ver->count; i++) {
  283. len = code_ver->versions[i].description.length;
  284. if (len > AMT_UNICODE_STRING_LEN) {
  285. status = AMT_STATUS_INTERNAL_ERROR;
  286. goto out;
  287. }
  288. len = code_ver->versions[i].version.length;
  289. if (code_ver->versions[i].version.string[len] != '\0' ||
  290. len != strlen(code_ver->versions[i].version.string)) {
  291. status = AMT_STATUS_INTERNAL_ERROR;
  292. goto out;
  293. }
  294. }
  295. out:
  296. return status;
  297. }
  298. static uint32_t amt_verify_response_header(uint32_t command,
  299. const struct amt_host_if_msg_header *resp_hdr,
  300. uint32_t response_size)
  301. {
  302. if (response_size < sizeof(struct amt_host_if_resp_header)) {
  303. return AMT_STATUS_INTERNAL_ERROR;
  304. } else if (response_size != (resp_hdr->length +
  305. sizeof(struct amt_host_if_msg_header))) {
  306. return AMT_STATUS_INTERNAL_ERROR;
  307. } else if (resp_hdr->command != command) {
  308. return AMT_STATUS_INTERNAL_ERROR;
  309. } else if (resp_hdr->_reserved != 0) {
  310. return AMT_STATUS_INTERNAL_ERROR;
  311. } else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
  312. resp_hdr->version.minor < AMT_MINOR_VERSION) {
  313. return AMT_STATUS_INTERNAL_ERROR;
  314. }
  315. return AMT_STATUS_SUCCESS;
  316. }
  317. static uint32_t amt_host_if_call(struct amt_host_if *acmd,
  318. const unsigned char *command, ssize_t command_sz,
  319. uint8_t **read_buf, uint32_t rcmd,
  320. unsigned int expected_sz)
  321. {
  322. uint32_t in_buf_sz;
  323. uint32_t out_buf_sz;
  324. ssize_t written;
  325. uint32_t status;
  326. struct amt_host_if_resp_header *msg_hdr;
  327. in_buf_sz = acmd->mei_cl.buf_size;
  328. *read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
  329. if (*read_buf == NULL)
  330. return AMT_STATUS_SDK_RESOURCES;
  331. memset(*read_buf, 0, in_buf_sz);
  332. msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
  333. written = mei_send_msg(&acmd->mei_cl,
  334. command, command_sz, acmd->send_timeout);
  335. if (written != command_sz)
  336. return AMT_STATUS_INTERNAL_ERROR;
  337. out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
  338. if (out_buf_sz <= 0)
  339. return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
  340. status = msg_hdr->status;
  341. if (status != AMT_STATUS_SUCCESS)
  342. return status;
  343. status = amt_verify_response_header(rcmd,
  344. &msg_hdr->header, out_buf_sz);
  345. if (status != AMT_STATUS_SUCCESS)
  346. return status;
  347. if (expected_sz && expected_sz != out_buf_sz)
  348. return AMT_STATUS_INTERNAL_ERROR;
  349. return AMT_STATUS_SUCCESS;
  350. }
  351. static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
  352. struct amt_code_versions *versions)
  353. {
  354. struct amt_host_if_resp_header *response = NULL;
  355. uint32_t status;
  356. status = amt_host_if_call(cmd,
  357. (const unsigned char *)&CODE_VERSION_REQ,
  358. sizeof(CODE_VERSION_REQ),
  359. (uint8_t **)&response,
  360. AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
  361. if (status != AMT_STATUS_SUCCESS)
  362. goto out;
  363. status = amt_verify_code_versions(response);
  364. if (status != AMT_STATUS_SUCCESS)
  365. goto out;
  366. memcpy(versions, response->data, sizeof(struct amt_code_versions));
  367. out:
  368. if (response != NULL)
  369. free(response);
  370. return status;
  371. }
  372. /************************** end of amt_host_if_command ***********************/
  373. int main(int argc, char **argv)
  374. {
  375. struct amt_code_versions ver;
  376. struct amt_host_if acmd;
  377. unsigned int i;
  378. uint32_t status;
  379. int ret;
  380. bool verbose;
  381. verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
  382. if (!amt_host_if_init(&acmd, 5000, verbose)) {
  383. ret = 1;
  384. goto out;
  385. }
  386. status = amt_get_code_versions(&acmd, &ver);
  387. amt_host_if_deinit(&acmd);
  388. switch (status) {
  389. case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
  390. printf("Intel AMT: DISABLED\n");
  391. ret = 0;
  392. break;
  393. case AMT_STATUS_SUCCESS:
  394. printf("Intel AMT: ENABLED\n");
  395. for (i = 0; i < ver.count; i++) {
  396. printf("%s:\t%s\n", ver.versions[i].description.string,
  397. ver.versions[i].version.string);
  398. }
  399. ret = 0;
  400. break;
  401. default:
  402. printf("An error has occurred\n");
  403. ret = 1;
  404. break;
  405. }
  406. out:
  407. return ret;
  408. }