0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 #include <stdio.h>
0068 #include <stdlib.h>
0069 #include <string.h>
0070 #include <fcntl.h>
0071 #include <sys/ioctl.h>
0072 #include <unistd.h>
0073 #include <errno.h>
0074 #include <stdint.h>
0075 #include <stdbool.h>
0076 #include <bits/wordsize.h>
0077 #include <linux/mei.h>
0078
0079
0080
0081
0082
0083 #define mei_msg(_me, fmt, ARGS...) do { \
0084 if (_me->verbose) \
0085 fprintf(stderr, fmt, ##ARGS); \
0086 } while (0)
0087
0088 #define mei_err(_me, fmt, ARGS...) do { \
0089 fprintf(stderr, "Error: " fmt, ##ARGS); \
0090 } while (0)
0091
0092 struct mei {
0093 uuid_le guid;
0094 bool initialized;
0095 bool verbose;
0096 unsigned int buf_size;
0097 unsigned char prot_ver;
0098 int fd;
0099 };
0100
0101 static void mei_deinit(struct mei *cl)
0102 {
0103 if (cl->fd != -1)
0104 close(cl->fd);
0105 cl->fd = -1;
0106 cl->buf_size = 0;
0107 cl->prot_ver = 0;
0108 cl->initialized = false;
0109 }
0110
0111 static bool mei_init(struct mei *me, const uuid_le *guid,
0112 unsigned char req_protocol_version, bool verbose)
0113 {
0114 int result;
0115 struct mei_client *cl;
0116 struct mei_connect_client_data data;
0117
0118 me->verbose = verbose;
0119
0120 me->fd = open("/dev/mei0", O_RDWR);
0121 if (me->fd == -1) {
0122 mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
0123 goto err;
0124 }
0125 memcpy(&me->guid, guid, sizeof(*guid));
0126 memset(&data, 0, sizeof(data));
0127 me->initialized = true;
0128
0129 memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
0130 result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
0131 if (result) {
0132 mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
0133 goto err;
0134 }
0135 cl = &data.out_client_properties;
0136 mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
0137 mei_msg(me, "protocol_version %d\n", cl->protocol_version);
0138
0139 if ((req_protocol_version > 0) &&
0140 (cl->protocol_version != req_protocol_version)) {
0141 mei_err(me, "Intel MEI protocol version not supported\n");
0142 goto err;
0143 }
0144
0145 me->buf_size = cl->max_msg_length;
0146 me->prot_ver = cl->protocol_version;
0147
0148 return true;
0149 err:
0150 mei_deinit(me);
0151 return false;
0152 }
0153
0154 static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
0155 ssize_t len, unsigned long timeout)
0156 {
0157 struct timeval tv;
0158 fd_set set;
0159 ssize_t rc;
0160
0161 tv.tv_sec = timeout / 1000;
0162 tv.tv_usec = (timeout % 1000) * 1000000;
0163
0164 mei_msg(me, "call read length = %zd\n", len);
0165
0166 FD_ZERO(&set);
0167 FD_SET(me->fd, &set);
0168 rc = select(me->fd + 1, &set, NULL, NULL, &tv);
0169 if (rc > 0 && FD_ISSET(me->fd, &set)) {
0170 mei_msg(me, "have reply\n");
0171 } else if (rc == 0) {
0172 rc = -1;
0173 mei_err(me, "read failed on timeout\n");
0174 goto out;
0175 } else {
0176 rc = errno;
0177 mei_err(me, "read failed on select with status %zd %s\n",
0178 rc, strerror(errno));
0179 goto out;
0180 }
0181
0182 rc = read(me->fd, buffer, len);
0183 if (rc < 0) {
0184 mei_err(me, "read failed with status %zd %s\n",
0185 rc, strerror(errno));
0186 goto out;
0187 }
0188
0189 mei_msg(me, "read succeeded with result %zd\n", rc);
0190
0191 out:
0192 if (rc < 0)
0193 mei_deinit(me);
0194
0195 return rc;
0196 }
0197
0198 static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
0199 ssize_t len, unsigned long timeout)
0200 {
0201 ssize_t written;
0202 ssize_t rc;
0203
0204 mei_msg(me, "call write length = %zd\n", len);
0205
0206 written = write(me->fd, buffer, len);
0207 if (written < 0) {
0208 rc = -errno;
0209 mei_err(me, "write failed with status %zd %s\n",
0210 written, strerror(errno));
0211 goto out;
0212 }
0213 mei_msg(me, "write success\n");
0214
0215 rc = written;
0216 out:
0217 if (rc < 0)
0218 mei_deinit(me);
0219
0220 return rc;
0221 }
0222
0223
0224
0225
0226
0227 #define AMT_MAJOR_VERSION 1
0228 #define AMT_MINOR_VERSION 1
0229
0230 #define AMT_STATUS_SUCCESS 0x0
0231 #define AMT_STATUS_INTERNAL_ERROR 0x1
0232 #define AMT_STATUS_NOT_READY 0x2
0233 #define AMT_STATUS_INVALID_AMT_MODE 0x3
0234 #define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
0235
0236 #define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000
0237 #define AMT_STATUS_SDK_RESOURCES 0x1004
0238
0239
0240 #define AMT_BIOS_VERSION_LEN 65
0241 #define AMT_VERSIONS_NUMBER 50
0242 #define AMT_UNICODE_STRING_LEN 20
0243
0244 struct amt_unicode_string {
0245 uint16_t length;
0246 char string[AMT_UNICODE_STRING_LEN];
0247 } __attribute__((packed));
0248
0249 struct amt_version_type {
0250 struct amt_unicode_string description;
0251 struct amt_unicode_string version;
0252 } __attribute__((packed));
0253
0254 struct amt_version {
0255 uint8_t major;
0256 uint8_t minor;
0257 } __attribute__((packed));
0258
0259 struct amt_code_versions {
0260 uint8_t bios[AMT_BIOS_VERSION_LEN];
0261 uint32_t count;
0262 struct amt_version_type versions[AMT_VERSIONS_NUMBER];
0263 } __attribute__((packed));
0264
0265
0266
0267
0268
0269 struct amt_host_if_msg_header {
0270 struct amt_version version;
0271 uint16_t _reserved;
0272 uint32_t command;
0273 uint32_t length;
0274 } __attribute__((packed));
0275
0276 struct amt_host_if_resp_header {
0277 struct amt_host_if_msg_header header;
0278 uint32_t status;
0279 unsigned char data[];
0280 } __attribute__((packed));
0281
0282 const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \
0283 0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
0284
0285 #define AMT_HOST_IF_CODE_VERSIONS_REQUEST 0x0400001A
0286 #define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
0287
0288 const struct amt_host_if_msg_header CODE_VERSION_REQ = {
0289 .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
0290 ._reserved = 0,
0291 .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
0292 .length = 0
0293 };
0294
0295
0296 struct amt_host_if {
0297 struct mei mei_cl;
0298 unsigned long send_timeout;
0299 bool initialized;
0300 };
0301
0302
0303 static bool amt_host_if_init(struct amt_host_if *acmd,
0304 unsigned long send_timeout, bool verbose)
0305 {
0306 acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
0307 acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
0308 return acmd->initialized;
0309 }
0310
0311 static void amt_host_if_deinit(struct amt_host_if *acmd)
0312 {
0313 mei_deinit(&acmd->mei_cl);
0314 acmd->initialized = false;
0315 }
0316
0317 static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
0318 {
0319 uint32_t status = AMT_STATUS_SUCCESS;
0320 struct amt_code_versions *code_ver;
0321 size_t code_ver_len;
0322 uint32_t ver_type_cnt;
0323 uint32_t len;
0324 uint32_t i;
0325
0326 code_ver = (struct amt_code_versions *)resp->data;
0327
0328 code_ver_len = resp->header.length - sizeof(uint32_t);
0329 ver_type_cnt = code_ver_len -
0330 sizeof(code_ver->bios) -
0331 sizeof(code_ver->count);
0332 if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
0333 status = AMT_STATUS_INTERNAL_ERROR;
0334 goto out;
0335 }
0336
0337 for (i = 0; i < code_ver->count; i++) {
0338 len = code_ver->versions[i].description.length;
0339
0340 if (len > AMT_UNICODE_STRING_LEN) {
0341 status = AMT_STATUS_INTERNAL_ERROR;
0342 goto out;
0343 }
0344
0345 len = code_ver->versions[i].version.length;
0346 if (code_ver->versions[i].version.string[len] != '\0' ||
0347 len != strlen(code_ver->versions[i].version.string)) {
0348 status = AMT_STATUS_INTERNAL_ERROR;
0349 goto out;
0350 }
0351 }
0352 out:
0353 return status;
0354 }
0355
0356 static uint32_t amt_verify_response_header(uint32_t command,
0357 const struct amt_host_if_msg_header *resp_hdr,
0358 uint32_t response_size)
0359 {
0360 if (response_size < sizeof(struct amt_host_if_resp_header)) {
0361 return AMT_STATUS_INTERNAL_ERROR;
0362 } else if (response_size != (resp_hdr->length +
0363 sizeof(struct amt_host_if_msg_header))) {
0364 return AMT_STATUS_INTERNAL_ERROR;
0365 } else if (resp_hdr->command != command) {
0366 return AMT_STATUS_INTERNAL_ERROR;
0367 } else if (resp_hdr->_reserved != 0) {
0368 return AMT_STATUS_INTERNAL_ERROR;
0369 } else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
0370 resp_hdr->version.minor < AMT_MINOR_VERSION) {
0371 return AMT_STATUS_INTERNAL_ERROR;
0372 }
0373 return AMT_STATUS_SUCCESS;
0374 }
0375
0376 static uint32_t amt_host_if_call(struct amt_host_if *acmd,
0377 const unsigned char *command, ssize_t command_sz,
0378 uint8_t **read_buf, uint32_t rcmd,
0379 unsigned int expected_sz)
0380 {
0381 uint32_t in_buf_sz;
0382 ssize_t out_buf_sz;
0383 ssize_t written;
0384 uint32_t status;
0385 struct amt_host_if_resp_header *msg_hdr;
0386
0387 in_buf_sz = acmd->mei_cl.buf_size;
0388 *read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
0389 if (*read_buf == NULL)
0390 return AMT_STATUS_SDK_RESOURCES;
0391 memset(*read_buf, 0, in_buf_sz);
0392 msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
0393
0394 written = mei_send_msg(&acmd->mei_cl,
0395 command, command_sz, acmd->send_timeout);
0396 if (written != command_sz)
0397 return AMT_STATUS_INTERNAL_ERROR;
0398
0399 out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
0400 if (out_buf_sz <= 0)
0401 return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
0402
0403 status = msg_hdr->status;
0404 if (status != AMT_STATUS_SUCCESS)
0405 return status;
0406
0407 status = amt_verify_response_header(rcmd,
0408 &msg_hdr->header, out_buf_sz);
0409 if (status != AMT_STATUS_SUCCESS)
0410 return status;
0411
0412 if (expected_sz && expected_sz != out_buf_sz)
0413 return AMT_STATUS_INTERNAL_ERROR;
0414
0415 return AMT_STATUS_SUCCESS;
0416 }
0417
0418
0419 static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
0420 struct amt_code_versions *versions)
0421 {
0422 struct amt_host_if_resp_header *response = NULL;
0423 uint32_t status;
0424
0425 status = amt_host_if_call(cmd,
0426 (const unsigned char *)&CODE_VERSION_REQ,
0427 sizeof(CODE_VERSION_REQ),
0428 (uint8_t **)&response,
0429 AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
0430
0431 if (status != AMT_STATUS_SUCCESS)
0432 goto out;
0433
0434 status = amt_verify_code_versions(response);
0435 if (status != AMT_STATUS_SUCCESS)
0436 goto out;
0437
0438 memcpy(versions, response->data, sizeof(struct amt_code_versions));
0439 out:
0440 if (response != NULL)
0441 free(response);
0442
0443 return status;
0444 }
0445
0446
0447 int main(int argc, char **argv)
0448 {
0449 struct amt_code_versions ver;
0450 struct amt_host_if acmd;
0451 unsigned int i;
0452 uint32_t status;
0453 int ret;
0454 bool verbose;
0455
0456 verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
0457
0458 if (!amt_host_if_init(&acmd, 5000, verbose)) {
0459 ret = 1;
0460 goto out;
0461 }
0462
0463 status = amt_get_code_versions(&acmd, &ver);
0464
0465 amt_host_if_deinit(&acmd);
0466
0467 switch (status) {
0468 case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
0469 printf("Intel AMT: DISABLED\n");
0470 ret = 0;
0471 break;
0472 case AMT_STATUS_SUCCESS:
0473 printf("Intel AMT: ENABLED\n");
0474 for (i = 0; i < ver.count; i++) {
0475 printf("%s:\t%s\n", ver.versions[i].description.string,
0476 ver.versions[i].version.string);
0477 }
0478 ret = 0;
0479 break;
0480 default:
0481 printf("An error has occurred\n");
0482 ret = 1;
0483 break;
0484 }
0485
0486 out:
0487 return ret;
0488 }