mei-amt-version.c 13 KB

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