Back to home page

OSCL-LXR

 
 

    


0001 /******************************************************************************
0002  * Intel Management Engine Interface (Intel MEI) Linux driver
0003  * Intel MEI Interface Header
0004  *
0005  * This file is provided under a dual BSD/GPLv2 license.  When using or
0006  * redistributing this file, you may do so under either license.
0007  *
0008  * GPL LICENSE SUMMARY
0009  *
0010  * Copyright(c) 2012 Intel Corporation. All rights reserved.
0011  *
0012  * This program is free software; you can redistribute it and/or modify
0013  * it under the terms of version 2 of the GNU General Public License as
0014  * published by the Free Software Foundation.
0015  *
0016  * This program is distributed in the hope that it will be useful, but
0017  * WITHOUT ANY WARRANTY; without even the implied warranty of
0018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0019  * General Public License for more details.
0020  *
0021  * You should have received a copy of the GNU General Public License
0022  * along with this program; if not, write to the Free Software
0023  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
0024  * USA
0025  *
0026  * The full GNU General Public License is included in this distribution
0027  * in the file called LICENSE.GPL.
0028  *
0029  * Contact Information:
0030  *  Intel Corporation.
0031  *  linux-mei@linux.intel.com
0032  *  http://www.intel.com
0033  *
0034  * BSD LICENSE
0035  *
0036  * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
0037  * All rights reserved.
0038  *
0039  * Redistribution and use in source and binary forms, with or without
0040  * modification, are permitted provided that the following conditions
0041  * are met:
0042  *
0043  *  * Redistributions of source code must retain the above copyright
0044  *    notice, this list of conditions and the following disclaimer.
0045  *  * Redistributions in binary form must reproduce the above copyright
0046  *    notice, this list of conditions and the following disclaimer in
0047  *    the documentation and/or other materials provided with the
0048  *    distribution.
0049  *  * Neither the name Intel Corporation nor the names of its
0050  *    contributors may be used to endorse or promote products derived
0051  *    from this software without specific prior written permission.
0052  *
0053  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0054  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0055  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0056  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0057  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0058  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0059  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0060  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0061  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0062  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0063  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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  * Intel Management Engine Interface
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 { /* rc < 0 */
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  * Intel Advanced Management Technology ME Client
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  * Intel Advanced Management Technology Host Interface
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     /* length - sizeof(status) */
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 /************************** end of amt_host_if_command ***********************/
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 }