> > Move misc-devices/mei examples to samples/mei and remove it from > Documentation Makefile. Delete misc-devices/Makefile. > > Create a new Makefile to build samples/mei. It can be built from top level > directory or from mei directory: > > Run make -C samples/mei or cd samples/mei; make > > Acked-by: Jonathan Corbet <corbet@xxxxxxx> > Signed-off-by: Shuah Khan <shuahkh@xxxxxxxxxxxxxxx> Acked-by: Tomas Winkler <tomas.winkler@xxxxxxxxx> > --- > Documentation/Makefile | 2 +- > Documentation/misc-devices/Makefile | 1 - > Documentation/misc-devices/mei/.gitignore | 1 - > Documentation/misc-devices/mei/Makefile | 5 - > Documentation/misc-devices/mei/TODO | 2 - > Documentation/misc-devices/mei/mei-amt-version.c | 479 -------------------- > --- > MAINTAINERS | 1 + > samples/mei/.gitignore | 1 + > samples/mei/Makefile | 9 + > samples/mei/TODO | 2 + > samples/mei/mei-amt-version.c | 479 > +++++++++++++++++++++++ > 11 files changed, 493 insertions(+), 489 deletions(-) delete mode 100644 > Documentation/misc-devices/Makefile > delete mode 100644 Documentation/misc-devices/mei/.gitignore > delete mode 100644 Documentation/misc-devices/mei/Makefile > delete mode 100644 Documentation/misc-devices/mei/TODO > delete mode 100644 Documentation/misc-devices/mei/mei-amt-version.c > create mode 100644 samples/mei/.gitignore create mode 100644 > samples/mei/Makefile create mode 100644 samples/mei/TODO create > mode 100644 samples/mei/mei-amt-version.c > > diff --git a/Documentation/Makefile b/Documentation/Makefile index > 80b5bdc..3c2a207 100644 > --- a/Documentation/Makefile > +++ b/Documentation/Makefile > @@ -1,2 +1,2 @@ > subdir-y := accounting auxdisplay blackfin \ > - laptops misc-devices pcmcia timers watchdog > + laptops pcmcia timers watchdog > diff --git a/Documentation/misc-devices/Makefile b/Documentation/misc- > devices/Makefile > deleted file mode 100644 > index e2b7aa4..0000000 > --- a/Documentation/misc-devices/Makefile > +++ /dev/null > @@ -1 +0,0 @@ > -subdir-y := mei > diff --git a/Documentation/misc-devices/mei/.gitignore > b/Documentation/misc-devices/mei/.gitignore > deleted file mode 100644 > index f356b81..0000000 > --- a/Documentation/misc-devices/mei/.gitignore > +++ /dev/null > @@ -1 +0,0 @@ > -mei-amt-version > diff --git a/Documentation/misc-devices/mei/Makefile > b/Documentation/misc-devices/mei/Makefile > deleted file mode 100644 > index d758047..0000000 > --- a/Documentation/misc-devices/mei/Makefile > +++ /dev/null > @@ -1,5 +0,0 @@ > -# List of programs to build > -hostprogs-y := mei-amt-version > -HOSTCFLAGS_mei-amt-version.o += -I$(objtree)/usr/include -# Tell kbuild > to always build the programs -always := $(hostprogs-y) diff --git > a/Documentation/misc-devices/mei/TODO b/Documentation/misc- > devices/mei/TODO > deleted file mode 100644 > index 6b3625d..0000000 > --- a/Documentation/misc-devices/mei/TODO > +++ /dev/null > @@ -1,2 +0,0 @@ > -TODO: > - - Cleanup and split the timer function > diff --git a/Documentation/misc-devices/mei/mei-amt-version.c > b/Documentation/misc-devices/mei/mei-amt-version.c > deleted file mode 100644 > index 57d0d87..0000000 > --- a/Documentation/misc-devices/mei/mei-amt-version.c > +++ /dev/null > @@ -1,479 +0,0 @@ > - > /********************************************************** > ******************** > - * Intel Management Engine Interface (Intel MEI) Linux driver > - * Intel MEI Interface Header > - * > - * This file is provided under a dual BSD/GPLv2 license. When using or > - * redistributing this file, you may do so under either license. > - * > - * GPL LICENSE SUMMARY > - * > - * Copyright(c) 2012 Intel Corporation. All rights reserved. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of version 2 of the GNU General Public License as > - * published by the Free Software Foundation. > - * > - * This program is distributed in the hope that it will be useful, but > - * WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > GNU > - * General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License > - * along with this program; if not, write to the Free Software > - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, > - * USA > - * > - * The full GNU General Public License is included in this distribution > - * in the file called LICENSE.GPL. > - * > - * Contact Information: > - * Intel Corporation. > - * linux-mei@xxxxxxxxxxxxxxx > - * http://www.intel.com > - * > - * BSD LICENSE > - * > - * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. > - * All rights reserved. > - * > - * Redistribution and use in source and binary forms, with or without > - * modification, are permitted provided that the following conditions > - * are met: > - * > - * * Redistributions of source code must retain the above copyright > - * notice, this list of conditions and the following disclaimer. > - * * Redistributions in binary form must reproduce the above copyright > - * notice, this list of conditions and the following disclaimer in > - * the documentation and/or other materials provided with the > - * distribution. > - * * Neither the name Intel Corporation nor the names of its > - * contributors may be used to endorse or promote products derived > - * from this software without specific prior written permission. > - * > - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > CONTRIBUTORS > - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT > NOT > - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND > FITNESS FOR > - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE > COPYRIGHT > - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, > INCIDENTAL, > - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT > NOT > - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS > OF USE, > - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED > AND ON ANY > - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF > THE USE > - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > DAMAGE. > - * > - > ********************************************************** > *******************/ > - > -#include <stdio.h> > -#include <stdlib.h> > -#include <string.h> > -#include <fcntl.h> > -#include <sys/ioctl.h> > -#include <unistd.h> > -#include <errno.h> > -#include <stdint.h> > -#include <stdbool.h> > -#include <bits/wordsize.h> > -#include <linux/mei.h> > - > - > /********************************************************** > ******************* > - * Intel Management Engine Interface > - > ********************************************************** > *******************/ > - > -#define mei_msg(_me, fmt, ARGS...) do { \ > - if (_me->verbose) \ > - fprintf(stderr, fmt, ##ARGS); \ > -} while (0) > - > -#define mei_err(_me, fmt, ARGS...) do { \ > - fprintf(stderr, "Error: " fmt, ##ARGS); \ > -} while (0) > - > -struct mei { > - uuid_le guid; > - bool initialized; > - bool verbose; > - unsigned int buf_size; > - unsigned char prot_ver; > - int fd; > -}; > - > -static void mei_deinit(struct mei *cl) > -{ > - if (cl->fd != -1) > - close(cl->fd); > - cl->fd = -1; > - cl->buf_size = 0; > - cl->prot_ver = 0; > - cl->initialized = false; > -} > - > -static bool mei_init(struct mei *me, const uuid_le *guid, > - unsigned char req_protocol_version, bool verbose) > -{ > - int result; > - struct mei_client *cl; > - struct mei_connect_client_data data; > - > - me->verbose = verbose; > - > - me->fd = open("/dev/mei", O_RDWR); > - if (me->fd == -1) { > - mei_err(me, "Cannot establish a handle to the Intel MEI > driver\n"); > - goto err; > - } > - memcpy(&me->guid, guid, sizeof(*guid)); > - memset(&data, 0, sizeof(data)); > - me->initialized = true; > - > - memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid)); > - result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data); > - if (result) { > - mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive > message. err=%d\n", result); > - goto err; > - } > - cl = &data.out_client_properties; > - mei_msg(me, "max_message_length %d\n", cl->max_msg_length); > - mei_msg(me, "protocol_version %d\n", cl->protocol_version); > - > - if ((req_protocol_version > 0) && > - (cl->protocol_version != req_protocol_version)) { > - mei_err(me, "Intel MEI protocol version not supported\n"); > - goto err; > - } > - > - me->buf_size = cl->max_msg_length; > - me->prot_ver = cl->protocol_version; > - > - return true; > -err: > - mei_deinit(me); > - return false; > -} > - > -static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer, > - ssize_t len, unsigned long timeout) > -{ > - ssize_t rc; > - > - mei_msg(me, "call read length = %zd\n", len); > - > - rc = read(me->fd, buffer, len); > - if (rc < 0) { > - mei_err(me, "read failed with status %zd %s\n", > - rc, strerror(errno)); > - mei_deinit(me); > - } else { > - mei_msg(me, "read succeeded with result %zd\n", rc); > - } > - return rc; > -} > - > -static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer, > - ssize_t len, unsigned long timeout) > -{ > - struct timeval tv; > - ssize_t written; > - ssize_t rc; > - fd_set set; > - > - tv.tv_sec = timeout / 1000; > - tv.tv_usec = (timeout % 1000) * 1000000; > - > - mei_msg(me, "call write length = %zd\n", len); > - > - written = write(me->fd, buffer, len); > - if (written < 0) { > - rc = -errno; > - mei_err(me, "write failed with status %zd %s\n", > - written, strerror(errno)); > - goto out; > - } > - > - FD_ZERO(&set); > - FD_SET(me->fd, &set); > - rc = select(me->fd + 1 , &set, NULL, NULL, &tv); > - if (rc > 0 && FD_ISSET(me->fd, &set)) { > - mei_msg(me, "write success\n"); > - } else if (rc == 0) { > - mei_err(me, "write failed on timeout with status\n"); > - goto out; > - } else { /* rc < 0 */ > - mei_err(me, "write failed on select with status %zd\n", rc); > - goto out; > - } > - > - rc = written; > -out: > - if (rc < 0) > - mei_deinit(me); > - > - return rc; > -} > - > - > /********************************************************** > ***************** > - * Intel Advanced Management Technology ME Client > - > ********************************************************** > *****************/ > - > -#define AMT_MAJOR_VERSION 1 > -#define AMT_MINOR_VERSION 1 > - > -#define AMT_STATUS_SUCCESS 0x0 > -#define AMT_STATUS_INTERNAL_ERROR 0x1 > -#define AMT_STATUS_NOT_READY 0x2 > -#define AMT_STATUS_INVALID_AMT_MODE 0x3 > -#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4 > - > -#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000 > -#define AMT_STATUS_SDK_RESOURCES 0x1004 > - > - > -#define AMT_BIOS_VERSION_LEN 65 > -#define AMT_VERSIONS_NUMBER 50 > -#define AMT_UNICODE_STRING_LEN 20 > - > -struct amt_unicode_string { > - uint16_t length; > - char string[AMT_UNICODE_STRING_LEN]; > -} __attribute__((packed)); > - > -struct amt_version_type { > - struct amt_unicode_string description; > - struct amt_unicode_string version; > -} __attribute__((packed)); > - > -struct amt_version { > - uint8_t major; > - uint8_t minor; > -} __attribute__((packed)); > - > -struct amt_code_versions { > - uint8_t bios[AMT_BIOS_VERSION_LEN]; > - uint32_t count; > - struct amt_version_type versions[AMT_VERSIONS_NUMBER]; > -} __attribute__((packed)); > - > - > /********************************************************** > ***************** > - * Intel Advanced Management Technology Host Interface > - > ********************************************************** > *****************/ > - > -struct amt_host_if_msg_header { > - struct amt_version version; > - uint16_t _reserved; > - uint32_t command; > - uint32_t length; > -} __attribute__((packed)); > - > -struct amt_host_if_resp_header { > - struct amt_host_if_msg_header header; > - uint32_t status; > - unsigned char data[0]; > -} __attribute__((packed)); > - > -const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \ > - 0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c); > - > -#define AMT_HOST_IF_CODE_VERSIONS_REQUEST 0x0400001A -#define > AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A > - > -const struct amt_host_if_msg_header CODE_VERSION_REQ = { > - .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION}, > - ._reserved = 0, > - .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST, > - .length = 0 > -}; > - > - > -struct amt_host_if { > - struct mei mei_cl; > - unsigned long send_timeout; > - bool initialized; > -}; > - > - > -static bool amt_host_if_init(struct amt_host_if *acmd, > - unsigned long send_timeout, bool verbose) > -{ > - acmd->send_timeout = (send_timeout) ? send_timeout : 20000; > - acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, > verbose); > - return acmd->initialized; > -} > - > -static void amt_host_if_deinit(struct amt_host_if *acmd) -{ > - mei_deinit(&acmd->mei_cl); > - acmd->initialized = false; > -} > - > -static uint32_t amt_verify_code_versions(const struct > amt_host_if_resp_header *resp) -{ > - uint32_t status = AMT_STATUS_SUCCESS; > - struct amt_code_versions *code_ver; > - size_t code_ver_len; > - uint32_t ver_type_cnt; > - uint32_t len; > - uint32_t i; > - > - code_ver = (struct amt_code_versions *)resp->data; > - /* length - sizeof(status) */ > - code_ver_len = resp->header.length - sizeof(uint32_t); > - ver_type_cnt = code_ver_len - > - sizeof(code_ver->bios) - > - sizeof(code_ver->count); > - if (code_ver->count != ver_type_cnt / sizeof(struct > amt_version_type)) { > - status = AMT_STATUS_INTERNAL_ERROR; > - goto out; > - } > - > - for (i = 0; i < code_ver->count; i++) { > - len = code_ver->versions[i].description.length; > - > - if (len > AMT_UNICODE_STRING_LEN) { > - status = AMT_STATUS_INTERNAL_ERROR; > - goto out; > - } > - > - len = code_ver->versions[i].version.length; > - if (code_ver->versions[i].version.string[len] != '\0' || > - len != strlen(code_ver->versions[i].version.string)) { > - status = AMT_STATUS_INTERNAL_ERROR; > - goto out; > - } > - } > -out: > - return status; > -} > - > -static uint32_t amt_verify_response_header(uint32_t command, > - const struct amt_host_if_msg_header > *resp_hdr, > - uint32_t response_size) > -{ > - if (response_size < sizeof(struct amt_host_if_resp_header)) { > - return AMT_STATUS_INTERNAL_ERROR; > - } else if (response_size != (resp_hdr->length + > - sizeof(struct amt_host_if_msg_header))) { > - return AMT_STATUS_INTERNAL_ERROR; > - } else if (resp_hdr->command != command) { > - return AMT_STATUS_INTERNAL_ERROR; > - } else if (resp_hdr->_reserved != 0) { > - return AMT_STATUS_INTERNAL_ERROR; > - } else if (resp_hdr->version.major != AMT_MAJOR_VERSION || > - resp_hdr->version.minor < AMT_MINOR_VERSION) { > - return AMT_STATUS_INTERNAL_ERROR; > - } > - return AMT_STATUS_SUCCESS; > -} > - > -static uint32_t amt_host_if_call(struct amt_host_if *acmd, > - const unsigned char *command, ssize_t > command_sz, > - uint8_t **read_buf, uint32_t rcmd, > - unsigned int expected_sz) > -{ > - uint32_t in_buf_sz; > - uint32_t out_buf_sz; > - ssize_t written; > - uint32_t status; > - struct amt_host_if_resp_header *msg_hdr; > - > - in_buf_sz = acmd->mei_cl.buf_size; > - *read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz); > - if (*read_buf == NULL) > - return AMT_STATUS_SDK_RESOURCES; > - memset(*read_buf, 0, in_buf_sz); > - msg_hdr = (struct amt_host_if_resp_header *)*read_buf; > - > - written = mei_send_msg(&acmd->mei_cl, > - command, command_sz, acmd- > >send_timeout); > - if (written != command_sz) > - return AMT_STATUS_INTERNAL_ERROR; > - > - out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, > 2000); > - if (out_buf_sz <= 0) > - return AMT_STATUS_HOST_IF_EMPTY_RESPONSE; > - > - status = msg_hdr->status; > - if (status != AMT_STATUS_SUCCESS) > - return status; > - > - status = amt_verify_response_header(rcmd, > - &msg_hdr->header, out_buf_sz); > - if (status != AMT_STATUS_SUCCESS) > - return status; > - > - if (expected_sz && expected_sz != out_buf_sz) > - return AMT_STATUS_INTERNAL_ERROR; > - > - return AMT_STATUS_SUCCESS; > -} > - > - > -static uint32_t amt_get_code_versions(struct amt_host_if *cmd, > - struct amt_code_versions *versions) > -{ > - struct amt_host_if_resp_header *response = NULL; > - uint32_t status; > - > - status = amt_host_if_call(cmd, > - (const unsigned char *)&CODE_VERSION_REQ, > - sizeof(CODE_VERSION_REQ), > - (uint8_t **)&response, > - AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0); > - > - if (status != AMT_STATUS_SUCCESS) > - goto out; > - > - status = amt_verify_code_versions(response); > - if (status != AMT_STATUS_SUCCESS) > - goto out; > - > - memcpy(versions, response->data, sizeof(struct > amt_code_versions)); > -out: > - if (response != NULL) > - free(response); > - > - return status; > -} > - > -/************************** end of amt_host_if_command > ***********************/ -int main(int argc, char **argv) -{ > - struct amt_code_versions ver; > - struct amt_host_if acmd; > - unsigned int i; > - uint32_t status; > - int ret; > - bool verbose; > - > - verbose = (argc > 1 && strcmp(argv[1], "-v") == 0); > - > - if (!amt_host_if_init(&acmd, 5000, verbose)) { > - ret = 1; > - goto out; > - } > - > - status = amt_get_code_versions(&acmd, &ver); > - > - amt_host_if_deinit(&acmd); > - > - switch (status) { > - case AMT_STATUS_HOST_IF_EMPTY_RESPONSE: > - printf("Intel AMT: DISABLED\n"); > - ret = 0; > - break; > - case AMT_STATUS_SUCCESS: > - printf("Intel AMT: ENABLED\n"); > - for (i = 0; i < ver.count; i++) { > - printf("%s:\t%s\n", ver.versions[i].description.string, > - ver.versions[i].version.string); > - } > - ret = 0; > - break; > - default: > - printf("An error has occurred\n"); > - ret = 1; > - break; > - } > - > -out: > - return ret; > -} > diff --git a/MAINTAINERS b/MAINTAINERS > index a5e1270..afd3577 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -6261,6 +6261,7 @@ F: include/linux/mei_cl_bus.h > F: drivers/misc/mei/* > F: drivers/watchdog/mei_wdt.c > F: Documentation/misc-devices/mei/* > +F: samples/mei/* > > INTEL MIC DRIVERS (mic) > M: Sudeep Dutt <sudeep.dutt@xxxxxxxxx> > diff --git a/samples/mei/.gitignore b/samples/mei/.gitignore new file mode > 100644 index 0000000..f356b81 > --- /dev/null > +++ b/samples/mei/.gitignore > @@ -0,0 +1 @@ > +mei-amt-version > diff --git a/samples/mei/Makefile b/samples/mei/Makefile new file mode > 100644 index 0000000..7aac216 > --- /dev/null > +++ b/samples/mei/Makefile > @@ -0,0 +1,9 @@ > +CC := $(CROSS_COMPILE)gcc > +CFLAGS := -I../../usr/include > + > +PROGS := mei-amt-version > + > +all: $(PROGS) > + > +clean: > + rm -fr $(PROGS) > diff --git a/samples/mei/TODO b/samples/mei/TODO new file mode 100644 > index 0000000..6b3625d > --- /dev/null > +++ b/samples/mei/TODO > @@ -0,0 +1,2 @@ > +TODO: > + - Cleanup and split the timer function > diff --git a/samples/mei/mei-amt-version.c b/samples/mei/mei-amt- > version.c new file mode 100644 index 0000000..57d0d87 > --- /dev/null > +++ b/samples/mei/mei-amt-version.c > @@ -0,0 +1,479 @@ > +/********************************************************* > ************* > +******** > + * Intel Management Engine Interface (Intel MEI) Linux driver > + * Intel MEI Interface Header > + * > + * This file is provided under a dual BSD/GPLv2 license. When using or > + * redistributing this file, you may do so under either license. > + * > + * GPL LICENSE SUMMARY > + * > + * Copyright(c) 2012 Intel Corporation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of version 2 of the GNU General Public License as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > GNU > + * General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, > + * USA > + * > + * The full GNU General Public License is included in this distribution > + * in the file called LICENSE.GPL. > + * > + * Contact Information: > + * Intel Corporation. > + * linux-mei@xxxxxxxxxxxxxxx > + * http://www.intel.com > + * > + * BSD LICENSE > + * > + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * > + * * Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * * Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in > + * the documentation and/or other materials provided with the > + * distribution. > + * * Neither the name Intel Corporation nor the names of its > + * contributors may be used to endorse or promote products derived > + * from this software without specific prior written permission. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT > NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND > FITNESS > +FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE > COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, > +INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT > NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS > OF > +USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED > AND ON > +ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF > THE > +USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > DAMAGE. > + * > + > +********************************************************* > ************** > +******/ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <fcntl.h> > +#include <sys/ioctl.h> > +#include <unistd.h> > +#include <errno.h> > +#include <stdint.h> > +#include <stdbool.h> > +#include <bits/wordsize.h> > +#include <linux/mei.h> > + > +/********************************************************* > ************* > +******* > + * Intel Management Engine Interface > + > +********************************************************* > ************** > +******/ > + > +#define mei_msg(_me, fmt, ARGS...) do { \ > + if (_me->verbose) \ > + fprintf(stderr, fmt, ##ARGS); \ > +} while (0) > + > +#define mei_err(_me, fmt, ARGS...) do { \ > + fprintf(stderr, "Error: " fmt, ##ARGS); \ } while (0) > + > +struct mei { > + uuid_le guid; > + bool initialized; > + bool verbose; > + unsigned int buf_size; > + unsigned char prot_ver; > + int fd; > +}; > + > +static void mei_deinit(struct mei *cl) > +{ > + if (cl->fd != -1) > + close(cl->fd); > + cl->fd = -1; > + cl->buf_size = 0; > + cl->prot_ver = 0; > + cl->initialized = false; > +} > + > +static bool mei_init(struct mei *me, const uuid_le *guid, > + unsigned char req_protocol_version, bool verbose) { > + int result; > + struct mei_client *cl; > + struct mei_connect_client_data data; > + > + me->verbose = verbose; > + > + me->fd = open("/dev/mei", O_RDWR); > + if (me->fd == -1) { > + mei_err(me, "Cannot establish a handle to the Intel MEI > driver\n"); > + goto err; > + } > + memcpy(&me->guid, guid, sizeof(*guid)); > + memset(&data, 0, sizeof(data)); > + me->initialized = true; > + > + memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid)); > + result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data); > + if (result) { > + mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive > message. err=%d\n", result); > + goto err; > + } > + cl = &data.out_client_properties; > + mei_msg(me, "max_message_length %d\n", cl->max_msg_length); > + mei_msg(me, "protocol_version %d\n", cl->protocol_version); > + > + if ((req_protocol_version > 0) && > + (cl->protocol_version != req_protocol_version)) { > + mei_err(me, "Intel MEI protocol version not supported\n"); > + goto err; > + } > + > + me->buf_size = cl->max_msg_length; > + me->prot_ver = cl->protocol_version; > + > + return true; > +err: > + mei_deinit(me); > + return false; > +} > + > +static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer, > + ssize_t len, unsigned long timeout) > +{ > + ssize_t rc; > + > + mei_msg(me, "call read length = %zd\n", len); > + > + rc = read(me->fd, buffer, len); > + if (rc < 0) { > + mei_err(me, "read failed with status %zd %s\n", > + rc, strerror(errno)); > + mei_deinit(me); > + } else { > + mei_msg(me, "read succeeded with result %zd\n", rc); > + } > + return rc; > +} > + > +static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer, > + ssize_t len, unsigned long timeout) > +{ > + struct timeval tv; > + ssize_t written; > + ssize_t rc; > + fd_set set; > + > + tv.tv_sec = timeout / 1000; > + tv.tv_usec = (timeout % 1000) * 1000000; > + > + mei_msg(me, "call write length = %zd\n", len); > + > + written = write(me->fd, buffer, len); > + if (written < 0) { > + rc = -errno; > + mei_err(me, "write failed with status %zd %s\n", > + written, strerror(errno)); > + goto out; > + } > + > + FD_ZERO(&set); > + FD_SET(me->fd, &set); > + rc = select(me->fd + 1 , &set, NULL, NULL, &tv); > + if (rc > 0 && FD_ISSET(me->fd, &set)) { > + mei_msg(me, "write success\n"); > + } else if (rc == 0) { > + mei_err(me, "write failed on timeout with status\n"); > + goto out; > + } else { /* rc < 0 */ > + mei_err(me, "write failed on select with status %zd\n", rc); > + goto out; > + } > + > + rc = written; > +out: > + if (rc < 0) > + mei_deinit(me); > + > + return rc; > +} > + > +/********************************************************* > ************* > +***** > + * Intel Advanced Management Technology ME Client > +********************************************************* > ************** > +****/ > + > +#define AMT_MAJOR_VERSION 1 > +#define AMT_MINOR_VERSION 1 > + > +#define AMT_STATUS_SUCCESS 0x0 > +#define AMT_STATUS_INTERNAL_ERROR 0x1 > +#define AMT_STATUS_NOT_READY 0x2 > +#define AMT_STATUS_INVALID_AMT_MODE 0x3 > +#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4 > + > +#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000 > +#define AMT_STATUS_SDK_RESOURCES 0x1004 > + > + > +#define AMT_BIOS_VERSION_LEN 65 > +#define AMT_VERSIONS_NUMBER 50 > +#define AMT_UNICODE_STRING_LEN 20 > + > +struct amt_unicode_string { > + uint16_t length; > + char string[AMT_UNICODE_STRING_LEN]; > +} __attribute__((packed)); > + > +struct amt_version_type { > + struct amt_unicode_string description; > + struct amt_unicode_string version; > +} __attribute__((packed)); > + > +struct amt_version { > + uint8_t major; > + uint8_t minor; > +} __attribute__((packed)); > + > +struct amt_code_versions { > + uint8_t bios[AMT_BIOS_VERSION_LEN]; > + uint32_t count; > + struct amt_version_type versions[AMT_VERSIONS_NUMBER]; } > +__attribute__((packed)); > + > +/********************************************************* > ************* > +***** > + * Intel Advanced Management Technology Host Interface > +********************************************************* > ************** > +****/ > + > +struct amt_host_if_msg_header { > + struct amt_version version; > + uint16_t _reserved; > + uint32_t command; > + uint32_t length; > +} __attribute__((packed)); > + > +struct amt_host_if_resp_header { > + struct amt_host_if_msg_header header; > + uint32_t status; > + unsigned char data[0]; > +} __attribute__((packed)); > + > +const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \ > + 0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c); > + > +#define AMT_HOST_IF_CODE_VERSIONS_REQUEST 0x0400001A #define > +AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A > + > +const struct amt_host_if_msg_header CODE_VERSION_REQ = { > + .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION}, > + ._reserved = 0, > + .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST, > + .length = 0 > +}; > + > + > +struct amt_host_if { > + struct mei mei_cl; > + unsigned long send_timeout; > + bool initialized; > +}; > + > + > +static bool amt_host_if_init(struct amt_host_if *acmd, > + unsigned long send_timeout, bool verbose) { > + acmd->send_timeout = (send_timeout) ? send_timeout : 20000; > + acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, > verbose); > + return acmd->initialized; > +} > + > +static void amt_host_if_deinit(struct amt_host_if *acmd) { > + mei_deinit(&acmd->mei_cl); > + acmd->initialized = false; > +} > + > +static uint32_t amt_verify_code_versions(const struct > +amt_host_if_resp_header *resp) { > + uint32_t status = AMT_STATUS_SUCCESS; > + struct amt_code_versions *code_ver; > + size_t code_ver_len; > + uint32_t ver_type_cnt; > + uint32_t len; > + uint32_t i; > + > + code_ver = (struct amt_code_versions *)resp->data; > + /* length - sizeof(status) */ > + code_ver_len = resp->header.length - sizeof(uint32_t); > + ver_type_cnt = code_ver_len - > + sizeof(code_ver->bios) - > + sizeof(code_ver->count); > + if (code_ver->count != ver_type_cnt / sizeof(struct > amt_version_type)) { > + status = AMT_STATUS_INTERNAL_ERROR; > + goto out; > + } > + > + for (i = 0; i < code_ver->count; i++) { > + len = code_ver->versions[i].description.length; > + > + if (len > AMT_UNICODE_STRING_LEN) { > + status = AMT_STATUS_INTERNAL_ERROR; > + goto out; > + } > + > + len = code_ver->versions[i].version.length; > + if (code_ver->versions[i].version.string[len] != '\0' || > + len != strlen(code_ver->versions[i].version.string)) { > + status = AMT_STATUS_INTERNAL_ERROR; > + goto out; > + } > + } > +out: > + return status; > +} > + > +static uint32_t amt_verify_response_header(uint32_t command, > + const struct amt_host_if_msg_header > *resp_hdr, > + uint32_t response_size) > +{ > + if (response_size < sizeof(struct amt_host_if_resp_header)) { > + return AMT_STATUS_INTERNAL_ERROR; > + } else if (response_size != (resp_hdr->length + > + sizeof(struct amt_host_if_msg_header))) { > + return AMT_STATUS_INTERNAL_ERROR; > + } else if (resp_hdr->command != command) { > + return AMT_STATUS_INTERNAL_ERROR; > + } else if (resp_hdr->_reserved != 0) { > + return AMT_STATUS_INTERNAL_ERROR; > + } else if (resp_hdr->version.major != AMT_MAJOR_VERSION || > + resp_hdr->version.minor < AMT_MINOR_VERSION) { > + return AMT_STATUS_INTERNAL_ERROR; > + } > + return AMT_STATUS_SUCCESS; > +} > + > +static uint32_t amt_host_if_call(struct amt_host_if *acmd, > + const unsigned char *command, ssize_t > command_sz, > + uint8_t **read_buf, uint32_t rcmd, > + unsigned int expected_sz) > +{ > + uint32_t in_buf_sz; > + uint32_t out_buf_sz; > + ssize_t written; > + uint32_t status; > + struct amt_host_if_resp_header *msg_hdr; > + > + in_buf_sz = acmd->mei_cl.buf_size; > + *read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz); > + if (*read_buf == NULL) > + return AMT_STATUS_SDK_RESOURCES; > + memset(*read_buf, 0, in_buf_sz); > + msg_hdr = (struct amt_host_if_resp_header *)*read_buf; > + > + written = mei_send_msg(&acmd->mei_cl, > + command, command_sz, acmd- > >send_timeout); > + if (written != command_sz) > + return AMT_STATUS_INTERNAL_ERROR; > + > + out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, > 2000); > + if (out_buf_sz <= 0) > + return AMT_STATUS_HOST_IF_EMPTY_RESPONSE; > + > + status = msg_hdr->status; > + if (status != AMT_STATUS_SUCCESS) > + return status; > + > + status = amt_verify_response_header(rcmd, > + &msg_hdr->header, out_buf_sz); > + if (status != AMT_STATUS_SUCCESS) > + return status; > + > + if (expected_sz && expected_sz != out_buf_sz) > + return AMT_STATUS_INTERNAL_ERROR; > + > + return AMT_STATUS_SUCCESS; > +} > + > + > +static uint32_t amt_get_code_versions(struct amt_host_if *cmd, > + struct amt_code_versions *versions) { > + struct amt_host_if_resp_header *response = NULL; > + uint32_t status; > + > + status = amt_host_if_call(cmd, > + (const unsigned char *)&CODE_VERSION_REQ, > + sizeof(CODE_VERSION_REQ), > + (uint8_t **)&response, > + AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0); > + > + if (status != AMT_STATUS_SUCCESS) > + goto out; > + > + status = amt_verify_code_versions(response); > + if (status != AMT_STATUS_SUCCESS) > + goto out; > + > + memcpy(versions, response->data, sizeof(struct > amt_code_versions)); > +out: > + if (response != NULL) > + free(response); > + > + return status; > +} > + > +/************************** end of amt_host_if_command > +***********************/ int main(int argc, char **argv) { > + struct amt_code_versions ver; > + struct amt_host_if acmd; > + unsigned int i; > + uint32_t status; > + int ret; > + bool verbose; > + > + verbose = (argc > 1 && strcmp(argv[1], "-v") == 0); > + > + if (!amt_host_if_init(&acmd, 5000, verbose)) { > + ret = 1; > + goto out; > + } > + > + status = amt_get_code_versions(&acmd, &ver); > + > + amt_host_if_deinit(&acmd); > + > + switch (status) { > + case AMT_STATUS_HOST_IF_EMPTY_RESPONSE: > + printf("Intel AMT: DISABLED\n"); > + ret = 0; > + break; > + case AMT_STATUS_SUCCESS: > + printf("Intel AMT: ENABLED\n"); > + for (i = 0; i < ver.count; i++) { > + printf("%s:\t%s\n", ver.versions[i].description.string, > + ver.versions[i].version.string); > + } > + ret = 0; > + break; > + default: > + printf("An error has occurred\n"); > + ret = 1; > + break; > + } > + > +out: > + return ret; > +} > -- > 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html