mei-amt-version.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  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. me->verbose = verbose;
  111. me->fd = open("/dev/mei0", O_RDWR);
  112. if (me->fd == -1) {
  113. mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
  114. goto err;
  115. }
  116. memcpy(&me->guid, guid, sizeof(*guid));
  117. memset(&data, 0, sizeof(data));
  118. me->initialized = true;
  119. memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
  120. result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
  121. if (result) {
  122. mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
  123. goto err;
  124. }
  125. cl = &data.out_client_properties;
  126. mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
  127. mei_msg(me, "protocol_version %d\n", cl->protocol_version);
  128. if ((req_protocol_version > 0) &&
  129. (cl->protocol_version != req_protocol_version)) {
  130. mei_err(me, "Intel MEI protocol version not supported\n");
  131. goto err;
  132. }
  133. me->buf_size = cl->max_msg_length;
  134. me->prot_ver = cl->protocol_version;
  135. return true;
  136. err:
  137. mei_deinit(me);
  138. return false;
  139. }
  140. static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
  141. ssize_t len, unsigned long timeout)
  142. {
  143. ssize_t rc;
  144. mei_msg(me, "call read length = %zd\n", len);
  145. rc = read(me->fd, buffer, len);
  146. if (rc < 0) {
  147. mei_err(me, "read failed with status %zd %s\n",
  148. rc, strerror(errno));
  149. mei_deinit(me);
  150. } else {
  151. mei_msg(me, "read succeeded with result %zd\n", rc);
  152. }
  153. return rc;
  154. }
  155. static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
  156. ssize_t len, unsigned long timeout)
  157. {
  158. struct timeval tv;
  159. ssize_t written;
  160. ssize_t rc;
  161. fd_set set;
  162. tv.tv_sec = timeout / 1000;
  163. tv.tv_usec = (timeout % 1000) * 1000000;
  164. mei_msg(me, "call write length = %zd\n", len);
  165. written = write(me->fd, buffer, len);
  166. if (written < 0) {
  167. rc = -errno;
  168. mei_err(me, "write failed with status %zd %s\n",
  169. written, strerror(errno));
  170. goto out;
  171. }
  172. FD_ZERO(&set);
  173. FD_SET(me->fd, &set);
  174. rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
  175. if (rc > 0 && FD_ISSET(me->fd, &set)) {
  176. mei_msg(me, "write success\n");
  177. } else if (rc == 0) {
  178. mei_err(me, "write failed on timeout with status\n");
  179. goto out;
  180. } else { /* rc < 0 */
  181. mei_err(me, "write failed on select with status %zd\n", rc);
  182. goto out;
  183. }
  184. rc = written;
  185. out:
  186. if (rc < 0)
  187. mei_deinit(me);
  188. return rc;
  189. }
  190. /***************************************************************************
  191. * Intel Advanced Management Technology ME Client
  192. ***************************************************************************/
  193. #define AMT_MAJOR_VERSION 1
  194. #define AMT_MINOR_VERSION 1
  195. #define AMT_STATUS_SUCCESS 0x0
  196. #define AMT_STATUS_INTERNAL_ERROR 0x1
  197. #define AMT_STATUS_NOT_READY 0x2
  198. #define AMT_STATUS_INVALID_AMT_MODE 0x3
  199. #define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
  200. #define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000
  201. #define AMT_STATUS_SDK_RESOURCES 0x1004
  202. #define AMT_BIOS_VERSION_LEN 65
  203. #define AMT_VERSIONS_NUMBER 50
  204. #define AMT_UNICODE_STRING_LEN 20
  205. struct amt_unicode_string {
  206. uint16_t length;
  207. char string[AMT_UNICODE_STRING_LEN];
  208. } __attribute__((packed));
  209. struct amt_version_type {
  210. struct amt_unicode_string description;
  211. struct amt_unicode_string version;
  212. } __attribute__((packed));
  213. struct amt_version {
  214. uint8_t major;
  215. uint8_t minor;
  216. } __attribute__((packed));
  217. struct amt_code_versions {
  218. uint8_t bios[AMT_BIOS_VERSION_LEN];
  219. uint32_t count;
  220. struct amt_version_type versions[AMT_VERSIONS_NUMBER];
  221. } __attribute__((packed));
  222. /***************************************************************************
  223. * Intel Advanced Management Technology Host Interface
  224. ***************************************************************************/
  225. struct amt_host_if_msg_header {
  226. struct amt_version version;
  227. uint16_t _reserved;
  228. uint32_t command;
  229. uint32_t length;
  230. } __attribute__((packed));
  231. struct amt_host_if_resp_header {
  232. struct amt_host_if_msg_header header;
  233. uint32_t status;
  234. unsigned char data[];
  235. } __attribute__((packed));
  236. const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \
  237. 0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
  238. #define AMT_HOST_IF_CODE_VERSIONS_REQUEST 0x0400001A
  239. #define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
  240. const struct amt_host_if_msg_header CODE_VERSION_REQ = {
  241. .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
  242. ._reserved = 0,
  243. .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
  244. .length = 0
  245. };
  246. struct amt_host_if {
  247. struct mei mei_cl;
  248. unsigned long send_timeout;
  249. bool initialized;
  250. };
  251. static bool amt_host_if_init(struct amt_host_if *acmd,
  252. unsigned long send_timeout, bool verbose)
  253. {
  254. acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
  255. acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
  256. return acmd->initialized;
  257. }
  258. static void amt_host_if_deinit(struct amt_host_if *acmd)
  259. {
  260. mei_deinit(&acmd->mei_cl);
  261. acmd->initialized = false;
  262. }
  263. static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
  264. {
  265. uint32_t status = AMT_STATUS_SUCCESS;
  266. struct amt_code_versions *code_ver;
  267. size_t code_ver_len;
  268. uint32_t ver_type_cnt;
  269. uint32_t len;
  270. uint32_t i;
  271. code_ver = (struct amt_code_versions *)resp->data;
  272. /* length - sizeof(status) */
  273. code_ver_len = resp->header.length - sizeof(uint32_t);
  274. ver_type_cnt = code_ver_len -
  275. sizeof(code_ver->bios) -
  276. sizeof(code_ver->count);
  277. if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
  278. status = AMT_STATUS_INTERNAL_ERROR;
  279. goto out;
  280. }
  281. for (i = 0; i < code_ver->count; i++) {
  282. len = code_ver->versions[i].description.length;
  283. if (len > AMT_UNICODE_STRING_LEN) {
  284. status = AMT_STATUS_INTERNAL_ERROR;
  285. goto out;
  286. }
  287. len = code_ver->versions[i].version.length;
  288. if (code_ver->versions[i].version.string[len] != '\0' ||
  289. len != strlen(code_ver->versions[i].version.string)) {
  290. status = AMT_STATUS_INTERNAL_ERROR;
  291. goto out;
  292. }
  293. }
  294. out:
  295. return status;
  296. }
  297. static uint32_t amt_verify_response_header(uint32_t command,
  298. const struct amt_host_if_msg_header *resp_hdr,
  299. uint32_t response_size)
  300. {
  301. if (response_size < sizeof(struct amt_host_if_resp_header)) {
  302. return AMT_STATUS_INTERNAL_ERROR;
  303. } else if (response_size != (resp_hdr->length +
  304. sizeof(struct amt_host_if_msg_header))) {
  305. return AMT_STATUS_INTERNAL_ERROR;
  306. } else if (resp_hdr->command != command) {
  307. return AMT_STATUS_INTERNAL_ERROR;
  308. } else if (resp_hdr->_reserved != 0) {
  309. return AMT_STATUS_INTERNAL_ERROR;
  310. } else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
  311. resp_hdr->version.minor < AMT_MINOR_VERSION) {
  312. return AMT_STATUS_INTERNAL_ERROR;
  313. }
  314. return AMT_STATUS_SUCCESS;
  315. }
  316. static uint32_t amt_host_if_call(struct amt_host_if *acmd,
  317. const unsigned char *command, ssize_t command_sz,
  318. uint8_t **read_buf, uint32_t rcmd,
  319. unsigned int expected_sz)
  320. {
  321. uint32_t in_buf_sz;
  322. ssize_t out_buf_sz;
  323. ssize_t written;
  324. uint32_t status;
  325. struct amt_host_if_resp_header *msg_hdr;
  326. in_buf_sz = acmd->mei_cl.buf_size;
  327. *read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
  328. if (*read_buf == NULL)
  329. return AMT_STATUS_SDK_RESOURCES;
  330. memset(*read_buf, 0, in_buf_sz);
  331. msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
  332. written = mei_send_msg(&acmd->mei_cl,
  333. command, command_sz, acmd->send_timeout);
  334. if (written != command_sz)
  335. return AMT_STATUS_INTERNAL_ERROR;
  336. out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
  337. if (out_buf_sz <= 0)
  338. return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
  339. status = msg_hdr->status;
  340. if (status != AMT_STATUS_SUCCESS)
  341. return status;
  342. status = amt_verify_response_header(rcmd,
  343. &msg_hdr->header, out_buf_sz);
  344. if (status != AMT_STATUS_SUCCESS)
  345. return status;
  346. if (expected_sz && expected_sz != out_buf_sz)
  347. return AMT_STATUS_INTERNAL_ERROR;
  348. return AMT_STATUS_SUCCESS;
  349. }
  350. static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
  351. struct amt_code_versions *versions)
  352. {
  353. struct amt_host_if_resp_header *response = NULL;
  354. uint32_t status;
  355. status = amt_host_if_call(cmd,
  356. (const unsigned char *)&CODE_VERSION_REQ,
  357. sizeof(CODE_VERSION_REQ),
  358. (uint8_t **)&response,
  359. AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
  360. if (status != AMT_STATUS_SUCCESS)
  361. goto out;
  362. status = amt_verify_code_versions(response);
  363. if (status != AMT_STATUS_SUCCESS)
  364. goto out;
  365. memcpy(versions, response->data, sizeof(struct amt_code_versions));
  366. out:
  367. if (response != NULL)
  368. free(response);
  369. return status;
  370. }
  371. /************************** end of amt_host_if_command ***********************/
  372. int main(int argc, char **argv)
  373. {
  374. struct amt_code_versions ver;
  375. struct amt_host_if acmd;
  376. unsigned int i;
  377. uint32_t status;
  378. int ret;
  379. bool verbose;
  380. verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
  381. if (!amt_host_if_init(&acmd, 5000, verbose)) {
  382. ret = 1;
  383. goto out;
  384. }
  385. status = amt_get_code_versions(&acmd, &ver);
  386. amt_host_if_deinit(&acmd);
  387. switch (status) {
  388. case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
  389. printf("Intel AMT: DISABLED\n");
  390. ret = 0;
  391. break;
  392. case AMT_STATUS_SUCCESS:
  393. printf("Intel AMT: ENABLED\n");
  394. for (i = 0; i < ver.count; i++) {
  395. printf("%s:\t%s\n", ver.versions[i].description.string,
  396. ver.versions[i].version.string);
  397. }
  398. ret = 0;
  399. break;
  400. default:
  401. printf("An error has occurred\n");
  402. ret = 1;
  403. break;
  404. }
  405. out:
  406. return ret;
  407. }