summaryrefslogtreecommitdiff
path: root/util/intelmetool
diff options
context:
space:
mode:
authorPhilipp Deppenwiese <zaolin@das-labor.org>2016-03-18 00:52:54 +0100
committerMartin Roth <martinroth@google.com>2016-03-25 18:28:03 +0100
commitd8fe4431ec7e158be1267ecece8d7d338a4b9703 (patch)
tree73214d353200b1d4d13f5f54602bd097a59ba498 /util/intelmetool
parent77e351d9d17cf8e8ad1c70200192ac59285b3096 (diff)
downloadcoreboot-d8fe4431ec7e158be1267ecece8d7d338a4b9703.tar.xz
util/intelmetool: Add intelmetool from Damien Zammit
The intelmetool shows information about the Intel Management Engine for different platforms. Original source code can be found under following link: https://github.com/zamaudio/intelmetool.git Change-Id: I0eb17833a21eb04cf9245a7312289a4102bec1a9 Signed-off-by: Philipp Deppenwiese <zaolin@das-labor.org> Reviewed-on: https://review.coreboot.org/14136 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'util/intelmetool')
-rw-r--r--util/intelmetool/Makefile87
-rw-r--r--util/intelmetool/intelmetool.c369
-rw-r--r--util/intelmetool/intelmetool.h276
-rw-r--r--util/intelmetool/me.c640
-rw-r--r--util/intelmetool/me.h408
-rw-r--r--util/intelmetool/me_status.c205
-rw-r--r--util/intelmetool/mmap.c58
-rw-r--r--util/intelmetool/mmap.h27
8 files changed, 2070 insertions, 0 deletions
diff --git a/util/intelmetool/Makefile b/util/intelmetool/Makefile
new file mode 100644
index 0000000000..4461f8615b
--- /dev/null
+++ b/util/intelmetool/Makefile
@@ -0,0 +1,87 @@
+# intelmetool
+
+# Copyright (C) 2013-2015 Damien Zammit <damien@zamaudio.com>
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or any later version.
+
+# 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.
+
+PROGRAM = intelmetool
+
+CC ?= gcc
+INSTALL ?= /usr/bin/install
+PREFIX ?= /usr/local
+CFLAGS ?= -O0 -g -Wall -W -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-sign-compare -Wno-unused-function
+LDFLAGS += -lpci -lz
+
+OBJS = intelmetool.o me.o me_status.o mmap.o
+
+OS_ARCH = $(shell uname)
+ifeq ($(OS_ARCH), Darwin)
+LDFLAGS += -framework DirectHW
+endif
+ifeq ($(OS_ARCH), FreeBSD)
+CFLAGS += -I/usr/local/include
+LDFLAGS += -L/usr/local/lib
+LIBS = -lz
+endif
+ifeq ($(OS_ARCH), NetBSD)
+CFLAGS += -I/usr/pkg/include
+LDFLAGS += -L/usr/pkg/lib -Wl,-rpath-link,/usr/pkg/lib -lz -lpciutils -lpci -l$(shell uname -p)
+endif
+
+all: pciutils dep $(PROGRAM)
+
+$(PROGRAM): $(OBJS)
+ $(CC) $(CFLAGS) -o $(PROGRAM) $(OBJS) $(LDFLAGS)
+
+clean:
+ rm -f $(PROGRAM) *.o *~ junit.xml
+
+distclean: clean
+ rm -f .dependencies
+
+dep:
+ @$(CC) $(CFLAGS) -MM *.c > .dependencies
+
+define LIBPCI_TEST
+/* Avoid a failing test due to libpci header symbol shadowing breakage */
+#define index shadow_workaround_index
+#ifdef __NetBSD__
+#include <pciutils/pci.h>
+#else
+#include <pci/pci.h>
+#endif
+struct pci_access *pacc;
+int main(int argc, char **argv)
+{
+ (void) argc;
+ (void) argv;
+ pacc = pci_alloc();
+ return 0;
+}
+endef
+export LIBPCI_TEST
+
+pciutils:
+ @printf "\nChecking for pciutils and zlib... "
+ @echo "$$LIBPCI_TEST" > .test.c
+ @$(CC) $(CFLAGS) .test.c -o .test $(LDFLAGS) >/dev/null 2>&1 && \
+ printf "found.\n" || ( printf "not found.\n\n"; \
+ printf "Please install pciutils-devel and zlib-devel.\n"; \
+ rm -f .test.c .test; exit 1)
+ @rm -rf .test.c .test .test.dSYM
+
+install: $(PROGRAM)
+ mkdir -p $(DESTDIR)$(PREFIX)/sbin
+ $(INSTALL) $(PROGRAM) $(DESTDIR)$(PREFIX)/sbin
+
+.PHONY: all clean distclean dep pciutils
+
+-include .dependencies
diff --git a/util/intelmetool/intelmetool.c b/util/intelmetool/intelmetool.c
new file mode 100644
index 0000000000..bde32041ff
--- /dev/null
+++ b/util/intelmetool/intelmetool.c
@@ -0,0 +1,369 @@
+/* intelmetool Dump interesting things about Management Engine even if hidden
+ * Copyright (C) 2014 Damien Zammit <damien@zamaudio.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#ifdef __NetBSD__
+#include <machine/sysarch.h>
+#endif
+
+#include "me.h"
+#include "mmap.h"
+#include "intelmetool.h"
+
+#define FD2 0x3428
+#define ME_COMMAND_DELAY 10000
+
+extern int fd_mem;
+int debug = 0;
+
+static uint32_t fd2 = 0;
+static const int size = 0x4000;
+static volatile uint8_t *rcba;
+
+static void dumpmem(uint8_t *phys, uint32_t size)
+{
+ uint32_t i;
+ printf("Dumping cloned ME memory:\n");
+ for (i = 0; i < size; i++) {
+ printf("%02X",*((uint8_t *) (phys + i)));
+ }
+ printf("\n");
+}
+
+static void zeroit(uint8_t *phys, uint32_t size)
+{
+ uint32_t i;
+ for (i = 0; i < size; i++) {
+ *((uint8_t *) (phys + i)) = 0x00;
+ }
+}
+
+static void dumpmemfile(uint8_t *phys, uint32_t size)
+{
+ FILE *fp = fopen("medump.bin", "w");
+ uint32_t i;
+ for (i = 0; i < size; i++) {
+ fprintf(fp, "%c", *((uint8_t *) (phys + i)));
+ }
+ fclose(fp);
+}
+
+static void rehide_me() {
+ if (fd2 & 0x2) {
+ printf("Re-hiding MEI device...");
+ fd2 = *(uint32_t *)(rcba + FD2);
+ *(uint32_t *)(rcba + FD2) = fd2 | 0x2;
+ printf("done, ");
+ }
+}
+
+/* You need >4GB total ram, in kernel cmdline, use 'mem=1000m'
+ * then this code will clone to absolute memory address 0xe0000000
+ * which can be read using a mmap tool at that offset.
+ * Real ME memory is located around top of memory minus 64MB. (I think)
+ * so we avoid cloning to this part.
+ */
+static void dump_me_memory() {
+ uint32_t me_clone = 0x60000000;
+ uint8_t *dump;
+
+ dump = map_physical_exact(me_clone, me_clone, 0x2000000);
+ zeroit(dump, 0x2000000);
+ printf("Send magic command for memory clone\n");
+
+ mei_reset();
+ usleep(ME_COMMAND_DELAY);
+ void* ptr = &me_clone;
+ int err = mkhi_debug_me_memory(ptr);
+
+ if (!err) {
+ printf("Wait a second...");
+ usleep(ME_COMMAND_DELAY);
+ printf("done\n\nHere are the first bytes:\n");
+ dumpmemfile(dump, 0x2000000);
+ //printf("Try reading 0x%zx with other mmap tool...\n"
+ // "Press enter to quit, you only get one chance to run this tool before reboot required for some reason\n", me_clone);
+ while (getc(stdin) != '\n') {};
+ unmap_physical(dump, 0x2000000);
+ }
+}
+
+static int pci_platform_scan() {
+ struct pci_access *pacc;
+ struct pci_dev *dev;
+ char namebuf[1024], *name;
+
+ pacc = pci_alloc();
+ pacc->method = PCI_ACCESS_I386_TYPE1;
+
+ pci_init(pacc);
+ pci_scan_bus(pacc);
+
+ for (dev=pacc->devices; dev; dev=dev->next) {
+ pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_CLASS);
+ name = pci_lookup_name(pacc, namebuf, sizeof(namebuf),
+ PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
+ if (dev->vendor_id == 0x8086) {
+ if (PCI_DEV_HAS_ME_DISABLE(dev->device_id)) {
+ printf(CGRN "Good news, you have a `%s` so ME is present but can be disabled, continuing...\n\n" RESET, name);
+ break;
+ } else if (PCI_DEV_HAS_ME_DIFFICULT(dev->device_id)) {
+ printf(CRED "Bad news, you have a `%s` so you have ME hardware on board and you can't control or disable it, continuing...\n\n" RESET, name);
+ break;
+ } else if (PCI_DEV_CAN_DISABLE_ME_IF_PRESENT(dev->device_id)) {
+ printf(CYEL "Not sure if ME hardware is present because you have a `%s`, but it is possible to disable it if you do, continuing...\n\n" RESET, name);
+ break;
+ } else if (PCI_DEV_ME_NOT_SURE(dev->device_id)) {
+ printf(CYEL "Found `%s`. Not sure whether you have ME hardware, exiting\n\n" RESET, name);
+ pci_cleanup(pacc);
+ return 1;
+ break;
+ }
+ }
+ }
+
+ if (!PCI_DEV_HAS_ME_DISABLE(dev->device_id) &&
+ !PCI_DEV_HAS_ME_DIFFICULT(dev->device_id) &&
+ !PCI_DEV_CAN_DISABLE_ME_IF_PRESENT(dev->device_id) &&
+ !PCI_DEV_ME_NOT_SURE(dev->device_id)) {
+ printf(CCYN "ME is not present on your board or unkown\n\n" RESET);
+ pci_cleanup(pacc);
+ return 1;
+ }
+
+ pci_cleanup(pacc);
+
+ return 0;
+}
+
+static struct pci_dev *pci_me_interface_scan(char **name) {
+ struct pci_access *pacc;
+ struct pci_dev *dev;
+ char namebuf[1024];
+
+ pacc = pci_alloc();
+ pacc->method = PCI_ACCESS_I386_TYPE1;
+
+ pci_init(pacc);
+ pci_scan_bus(pacc);
+
+ for (dev=pacc->devices; dev; dev=dev->next) {
+ pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_CLASS);
+ *name = pci_lookup_name(pacc, namebuf, sizeof(namebuf),
+ PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
+ if (dev->vendor_id == 0x8086) {
+ if (PCI_DEV_HAS_SUPPORTED_ME(dev->device_id)) {
+ break;
+ }
+ }
+ }
+
+ if (!PCI_DEV_HAS_SUPPORTED_ME(dev->device_id)) {
+ rehide_me();
+
+ printf("MEI device not found\n");
+ pci_cleanup(pacc);
+ return NULL;
+ }
+
+ return dev;
+}
+
+static int activate_me() {
+ struct pci_access *pacc;
+ struct pci_dev *sb;
+ uint32_t rcba_phys;
+
+ pacc = pci_alloc();
+ pacc->method = PCI_ACCESS_I386_TYPE1;
+
+ pci_init(pacc);
+ pci_scan_bus(pacc);
+
+ sb = pci_get_dev(pacc, 0, 0, 0x1f, 0);
+ if (!sb) {
+ printf("Uh oh, southbridge not on BDF(0:31:0), please report this error, exiting.\n");
+ pci_cleanup(pacc);
+ return 1;
+ }
+ pci_fill_info(sb, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_CLASS);
+
+ rcba_phys = pci_read_long(sb, 0xf0) & 0xfffffffe;
+ rcba = map_physical(rcba_phys, size);
+
+ //printf("RCBA at 0x%08" PRIx32 "\n", (uint32_t)rcba_phys);
+ fd2 = *(uint32_t *)(rcba + FD2);
+ *(uint32_t *)(rcba + FD2) = fd2 & ~0x2;
+ if (fd2 & 0x2) {
+ printf("MEI was hidden on PCI, now unlocked\n");
+ } else {
+ printf("MEI not hidden on PCI, checking if visible\n");
+ }
+
+ pci_cleanup(pacc);
+
+ return 0;
+}
+
+static void dump_me_info() {
+ struct pci_dev *dev;
+ uint32_t stat, stat2;
+ char *name;
+
+ if (pci_platform_scan()) {
+ exit(1);
+ }
+
+ dev = pci_me_interface_scan(&name);
+ if (!dev) {
+ exit(1);
+ }
+
+ if (activate_me()) {
+ exit(1);
+ }
+
+ printf("MEI found: [%x:%x] %s\n\n", dev->vendor_id, dev->device_id, name);
+ stat = pci_read_long(dev, 0x40);
+ printf("ME Status : 0x%x\n", stat);
+ stat2 = pci_read_long(dev, 0x48);
+ printf("ME Status 2 : 0x%x\n\n", stat2);
+
+ intel_me_status(stat, stat2);
+ printf("\n");
+ intel_me_extend_valid(dev);
+ printf("\n");
+
+ if ((stat & 0xf000) >> 12 != 0) {
+ printf("ME: has a broken implementation on your board with this BIOS\n");
+ }
+
+ intel_mei_setup(dev);
+ usleep(ME_COMMAND_DELAY);
+ mei_reset();
+ usleep(ME_COMMAND_DELAY);
+ mkhi_get_fw_version();
+ usleep(ME_COMMAND_DELAY);
+ mei_reset();
+ usleep(ME_COMMAND_DELAY);
+ mkhi_get_fwcaps();
+ usleep(ME_COMMAND_DELAY);
+
+ rehide_me();
+
+ munmap((void*)rcba, size);
+}
+
+static void print_version(void)
+{
+ printf("intelmetool v%s -- ", INTELMETOOL_VERSION);
+ printf("Copyright (C) 2015 Damien Zammit\n\n");
+ printf(
+ "This program is free software: you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation, version 2 of the License.\n\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n\n");
+}
+
+static void print_usage(const char *name)
+{
+ printf("usage: %s [-vh?sd]\n", name);
+ printf("\n"
+ " -v | --version: print the version\n"
+ " -h | --help: print this help\n\n"
+ " -s | --show: dump all me information on console\n"
+ " -d | --debug: enable debug output\n"
+ "\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int opt, option_index = 0;
+ unsigned cmd_exec = 0;
+
+ static struct option long_options[] = {
+ {"version", 0, 0, 'v'},
+ {"help", 0, 0, 'h'},
+ {"show", 0, 0, 's'},
+ {"debug", 0, 0, 'd'},
+ {0, 0, 0, 0}
+ };
+
+ while ((opt = getopt_long(argc, argv, "vh?sd",
+ long_options, &option_index)) != EOF) {
+ switch (opt) {
+ case 'v':
+ print_version();
+ exit(0);
+ break;
+ case 's':
+ cmd_exec = 1;
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'h':
+ case '?':
+ default:
+ print_usage(argv[0]);
+ exit(0);
+ break;
+ }
+ }
+
+ #if defined(__FreeBSD__)
+ if (open("/dev/io", O_RDWR) < 0) {
+ perror("/dev/io");
+ #elif defined(__NetBSD__)
+ # ifdef __i386__
+ if (i386_iopl(3)) {
+ perror("iopl");
+ # else
+ if (x86_64_iopl(3)) {
+ perror("iopl");
+ # endif
+ #else
+ if (iopl(3)) {
+ perror("iopl");
+ #endif
+ printf("You need to be root.\n");
+ exit(1);
+ }
+
+ #ifndef __DARWIN__
+ if ((fd_mem = open("/dev/mem", O_RDWR)) < 0) {
+ perror("Can not open /dev/mem");
+ exit(1);
+ }
+ #endif
+
+ switch(cmd_exec) {
+ case 1:
+ dump_me_info();
+ break;
+ default:
+ print_usage(argv[0]);
+ break;
+ }
+
+ return 0;
+}
diff --git a/util/intelmetool/intelmetool.h b/util/intelmetool/intelmetool.h
new file mode 100644
index 0000000000..22cff1a27b
--- /dev/null
+++ b/util/intelmetool/intelmetool.h
@@ -0,0 +1,276 @@
+/*
+ * intelmetool
+ *
+ * Copyright (C) 2008-2010 by coresystems GmbH
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2015 Damien Zammit
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ */
+
+#define ME_NOT_PRESENT 0
+#define ME_FOUND_NOTHING 1
+#define ME_FOUND_SOMETHING_NOT_SURE 2
+#define ME_CAN_DISABLE_IF_PRESENT 3
+#define ME_PRESENT_CAN_DISABLE 4
+#define ME_PRESENT_CANNOT_DISABLE 5
+
+#define INTELMETOOL_VERSION "1.0"
+
+#if defined(__GLIBC__)
+#include <sys/io.h>
+#endif
+#if (defined(__MACH__) && defined(__APPLE__))
+/* DirectHW is available here: http://www.coreboot.org/DirectHW */
+#define __DARWIN__
+#include <DirectHW/DirectHW.h>
+#endif
+#ifdef __NetBSD__
+#include <pciutils/pci.h>
+#else
+#include <pci/pci.h>
+#endif
+
+#define CNRM "\x1B[0m"
+#define CRED "\x1B[31m"
+#define CGRN "\x1B[32m"
+#define CYEL "\x1B[33m"
+#define CBLU "\x1B[34m"
+#define CMAG "\x1B[35m"
+#define CCYN "\x1B[36m"
+#define CWHT "\x1B[37m"
+#define RESET "\033[0m"
+
+extern int debug;
+
+// Definitely has ME and can be disabled
+#define PCI_DEVICE_ID_INTEL_ICH8ME 0x2811
+#define PCI_DEVICE_ID_INTEL_ICH9ME 0x2917
+#define PCI_DEVICE_ID_INTEL_ICH9M 0x2919
+
+#define PCI_DEV_HAS_ME_DISABLE(x) ( \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH8ME ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH9ME ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH9M ))
+
+// Definitely has ME and is very difficult to remove
+#define PCI_DEVICE_ID_INTEL_ICH10R 0x3a16
+#define PCI_DEVICE_ID_INTEL_3400_DESKTOP 0x3b00
+#define PCI_DEVICE_ID_INTEL_3400_MOBILE 0x3b01
+#define PCI_DEVICE_ID_INTEL_P55 0x3b02
+#define PCI_DEVICE_ID_INTEL_PM55 0x3b03
+#define PCI_DEVICE_ID_INTEL_H55 0x3b06
+#define PCI_DEVICE_ID_INTEL_QM57 0x3b07
+#define PCI_DEVICE_ID_INTEL_H57 0x3b08
+#define PCI_DEVICE_ID_INTEL_HM55 0x3b09
+#define PCI_DEVICE_ID_INTEL_Q57 0x3b0a
+#define PCI_DEVICE_ID_INTEL_HM57 0x3b0b
+#define PCI_DEVICE_ID_INTEL_3400_MOBILE_SFF 0x3b0d
+#define PCI_DEVICE_ID_INTEL_B55_A 0x3b0e
+#define PCI_DEVICE_ID_INTEL_QS57 0x3b0f
+#define PCI_DEVICE_ID_INTEL_3400 0x3b12
+#define PCI_DEVICE_ID_INTEL_3420 0x3b14
+#define PCI_DEVICE_ID_INTEL_3450 0x3b16
+#define PCI_DEVICE_ID_INTEL_B55_B 0x3b1e
+#define PCI_DEVICE_ID_INTEL_Z68 0x1c44
+#define PCI_DEVICE_ID_INTEL_P67 0x1c46
+#define PCI_DEVICE_ID_INTEL_UM67 0x1c47
+#define PCI_DEVICE_ID_INTEL_HM65 0x1c49
+#define PCI_DEVICE_ID_INTEL_H67 0x1c4a
+#define PCI_DEVICE_ID_INTEL_HM67 0x1c4b
+#define PCI_DEVICE_ID_INTEL_Q65 0x1c4c
+#define PCI_DEVICE_ID_INTEL_QS67 0x1c4d
+#define PCI_DEVICE_ID_INTEL_Q67 0x1c4e
+#define PCI_DEVICE_ID_INTEL_QM67 0x1c4f
+#define PCI_DEVICE_ID_INTEL_B65 0x1c50
+#define PCI_DEVICE_ID_INTEL_C202 0x1c52
+#define PCI_DEVICE_ID_INTEL_C204 0x1c54
+#define PCI_DEVICE_ID_INTEL_C206 0x1c56
+#define PCI_DEVICE_ID_INTEL_H61 0x1c5c
+#define PCI_DEVICE_ID_INTEL_Z77 0x1e44
+#define PCI_DEVICE_ID_INTEL_Z75 0x1e46
+#define PCI_DEVICE_ID_INTEL_Q77 0x1e47
+#define PCI_DEVICE_ID_INTEL_Q75 0x1e48
+#define PCI_DEVICE_ID_INTEL_B75 0x1e49
+#define PCI_DEVICE_ID_INTEL_H77 0x1e4a
+#define PCI_DEVICE_ID_INTEL_C216 0x1e53
+#define PCI_DEVICE_ID_INTEL_QM77 0x1e55
+#define PCI_DEVICE_ID_INTEL_QS77 0x1e56
+#define PCI_DEVICE_ID_INTEL_HM77 0x1e57
+#define PCI_DEVICE_ID_INTEL_UM77 0x1e58
+#define PCI_DEVICE_ID_INTEL_HM76 0x1e59
+#define PCI_DEVICE_ID_INTEL_HM75 0x1e5d
+#define PCI_DEVICE_ID_INTEL_HM70 0x1e5e
+#define PCI_DEVICE_ID_INTEL_NM70 0x1e5f
+#define PCI_DEVICE_ID_INTEL_QM87 0x8c4f
+#define PCI_DEVICE_ID_INTEL_DH89XXCC 0x2310
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_FULL 0x9c41
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_PREM 0x9c43
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_BASE 0x9c45
+
+#define PCI_DEV_HAS_ME_DIFFICULT(x) ( \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH10R ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_3400_DESKTOP ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_3400_MOBILE ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_P55 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_PM55 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_H55 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_QM57 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_H57 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_HM55 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_Q57 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_HM57 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_3400_MOBILE_SFF ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_B55_A ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_QS57 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_3400 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_3420 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_3450 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_B55_B ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_Z68 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_P67 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_UM67 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_HM65 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_H67 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_HM67 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_Q65 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_QS67 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_Q67 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_QM67 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_B65 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_C202 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_C204 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_C206 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_H61 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_Z77 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_Z75 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_Q77 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_Q75 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_B75 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_H77 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_C216 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_QM77 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_QS77 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_HM77 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_UM77 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_HM76 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_HM75 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_HM70 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_NM70 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_QM87 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_DH89XXCC ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_FULL ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_PREM ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_BASE ))
+
+// Not sure if ME present, but should be able to disable it easily
+#define PCI_DEVICE_ID_INTEL_ICH8 0x2810
+#define PCI_DEVICE_ID_INTEL_ICH8M 0x2815
+#define PCI_DEVICE_ID_INTEL_ICH9DH 0x2912
+#define PCI_DEVICE_ID_INTEL_ICH9DO 0x2914
+#define PCI_DEVICE_ID_INTEL_ICH9R 0x2916
+#define PCI_DEVICE_ID_INTEL_ICH9 0x2918
+
+#define PCI_DEV_CAN_DISABLE_ME_IF_PRESENT(x) ( \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH8 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH8M ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH9DH ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH9DO ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH9R ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_ICH9 ))
+
+// Not sure at all
+#define PCI_DEVICE_ID_INTEL_SCH_POULSBO_LPC 0x8119
+#define PCI_DEVICE_ID_INTEL_SCH_POULSBO 0x8100
+
+#define PCI_DEV_ME_NOT_SURE(x) ( \
+ ( (x) == PCI_DEVICE_ID_INTEL_SCH_POULSBO_LPC ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_SCH_POULSBO))
+
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_1 0x1C3A /* Cougar Point */
+#define PCI_DEVICE_ID_INTEL_PATSBURG_1 0x1D3A /* C600/X79 Patsburg */
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_1 0x1CBA /* Panther Point */
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_2 0x1DBA /* Panther Point */
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_3 0x1E3A /* Panther Point */
+#define PCI_DEVICE_ID_INTEL_CAVECREEK 0x2364 /* Cave Creek */
+#define PCI_DEVICE_ID_INTEL_BEARLAKE_1 0x28B4 /* Bearlake */
+#define PCI_DEVICE_ID_INTEL_BEARLAKE_2 0x28C4 /* Bearlake */
+#define PCI_DEVICE_ID_INTEL_BEARLAKE_3 0x28D4 /* Bearlake */
+#define PCI_DEVICE_ID_INTEL_BEARLAKE_4 0x28E4 /* Bearlake */
+#define PCI_DEVICE_ID_INTEL_BEARLAKE_5 0x28F4 /* Bearlake */
+#define PCI_DEVICE_ID_INTEL_82946GZ 0x2974 /* 82946GZ/GL */
+#define PCI_DEVICE_ID_INTEL_82G35 0x2984 /* 82G35 Express */
+#define PCI_DEVICE_ID_INTEL_82Q963 0x2994 /* 82Q963/Q965 */
+#define PCI_DEVICE_ID_INTEL_82P965 0x29A4 /* 82P965/G965 */
+#define PCI_DEVICE_ID_INTEL_82Q35 0x29B4 /* 82Q35 Express */
+#define PCI_DEVICE_ID_INTEL_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */
+#define PCI_DEVICE_ID_INTEL_82Q33 0x29D4 /* 82Q33 Express */
+#define PCI_DEVICE_ID_INTEL_82X38 0x29E4 /* 82X38/X48 Express */
+#define PCI_DEVICE_ID_INTEL_3200 0x29F4 /* 3200/3210 Server */
+#define PCI_DEVICE_ID_INTEL_PM965 0x2A04 /* Mobile PM965/GM965 */
+#define PCI_DEVICE_ID_INTEL_GME965 0x2A14 /* Mobile GME965/GLE960 */
+#define PCI_DEVICE_ID_INTEL_CANTIGA_1 0x2A44 /* Cantiga */
+#define PCI_DEVICE_ID_INTEL_CANTIGA_2 0x2a50 /* Cantiga */
+#define PCI_DEVICE_ID_INTEL_CANTIGA_3 0x2A54 /* Cantiga */
+#define PCI_DEVICE_ID_INTEL_CANTIGA_4 0x2A64 /* Cantiga */
+#define PCI_DEVICE_ID_INTEL_CANTIGA_5 0x2A74 /* Cantiga */
+#define PCI_DEVICE_ID_INTEL_EAGLELAKE_1 0x2E04 /* Eaglelake */
+#define PCI_DEVICE_ID_INTEL_EAGLELAKE_2 0x2E14 /* Eaglelake */
+#define PCI_DEVICE_ID_INTEL_EAGLELAKE_3 0x2E24 /* Eaglelake */
+#define PCI_DEVICE_ID_INTEL_EAGLELAKE_4 0x2E34 /* Eaglelake */
+#define PCI_DEVICE_ID_INTEL_CALPELLA_1 0x3B64 /* Calpella */
+#define PCI_DEVICE_ID_INTEL_CALPELLA_2 0x3B65 /* Calpella */
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_1 0x8C3A /* Lynx Point H */
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_2 0x8CBA /* Lynx Point H Refresh */
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_3 0x8D3A /* Lynx Point - Wellsburg */
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_4 0x9C3A /* Lynx Point LP */
+#define PCI_DEVICE_ID_INTEL_WILDCAT_1 0x9CBA /* Wildcat Point LP */
+#define PCI_DEVICE_ID_INTEL_WILDCAT_2 0x9CBB /* Wildcat Point LP 2 */
+
+#define PCI_DEV_HAS_SUPPORTED_ME(x) ( \
+ ( (x) == PCI_DEVICE_ID_INTEL_COUGARPOINT_1 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_PATSBURG_1 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_PANTHERPOINT_1 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_PANTHERPOINT_2 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_PANTHERPOINT_3 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_CAVECREEK ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_BEARLAKE_1 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_BEARLAKE_2 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_BEARLAKE_3 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_BEARLAKE_4 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_BEARLAKE_5 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_82946GZ ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_82G35 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_82Q963 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_82P965 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_82Q35 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_82G33 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_82Q33 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_82X38 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_3200 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_PM965 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_GME965 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_CANTIGA_1 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_CANTIGA_2 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_CANTIGA_3 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_CANTIGA_4 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_CANTIGA_5 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_EAGLELAKE_1 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_EAGLELAKE_2 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_EAGLELAKE_3 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_EAGLELAKE_4 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_CALPELLA_1 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_CALPELLA_2 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_LYNXPOINT_1 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_LYNXPOINT_2 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_LYNXPOINT_3 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_LYNXPOINT_4 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_WILDCAT_1 ) || \
+ ( (x) == PCI_DEVICE_ID_INTEL_WILDCAT_2))
diff --git a/util/intelmetool/me.c b/util/intelmetool/me.c
new file mode 100644
index 0000000000..da5fb71643
--- /dev/null
+++ b/util/intelmetool/me.c
@@ -0,0 +1,640 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * 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.
+ */
+
+#include <pci/pci.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/io.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "me.h"
+#include "mmap.h"
+#include "intelmetool.h"
+
+#define read32(addr, off) ( *((uint32_t *) (addr + off)) )
+#define write32(addr, off, val) ( *((uint32_t *) (addr + off)) = val)
+
+/* Path that the BIOS should take based on ME state */
+/*
+static const char *me_bios_path_values[] = {
+ [ME_NORMAL_BIOS_PATH] = "Normal",
+ [ME_S3WAKE_BIOS_PATH] = "S3 Wake",
+ [ME_ERROR_BIOS_PATH] = "Error",
+ [ME_RECOVERY_BIOS_PATH] = "Recovery",
+ [ME_DISABLE_BIOS_PATH] = "Disable",
+ [ME_FIRMWARE_UPDATE_BIOS_PATH] = "Firmware Update",
+};
+*/
+
+/* MMIO base address for MEI interface */
+static uint32_t mei_base_address;
+static uint8_t* mei_mmap;
+
+static void mei_dump(void *ptr, int dword, int offset, const char *type)
+{
+ struct mei_csr *csr;
+
+
+ switch (offset) {
+ case MEI_H_CSR:
+ case MEI_ME_CSR_HA:
+ csr = ptr;
+/* if (!csr) {
+ printf("%-9s[%02x] : ", type, offset);
+ printf("ERROR: 0x%08x\n", dword);
+ break;
+ }
+ printf("%-9s[%02x] : ", type, offset);
+ printf("depth=%u read=%02u write=%02u ready=%u "
+ "reset=%u intgen=%u intstatus=%u intenable=%u\n", csr->buffer_depth,
+ csr->buffer_read_ptr, csr->buffer_write_ptr,
+ csr->ready, csr->reset, csr->interrupt_generate,
+ csr->interrupt_status, csr->interrupt_enable);
+*/ break;
+ case MEI_ME_CB_RW:
+ case MEI_H_CB_WW:
+ printf("%-9s[%02x] : ", type, offset);
+ printf("CB: 0x%08x\n", dword);
+ break;
+ default:
+ printf("%-9s[%02x] : ", type, offset);
+ printf("0x%08x\n", offset);
+ break;
+ }
+}
+
+/*
+ * ME/MEI access helpers using memcpy to avoid aliasing.
+ */
+
+static inline void mei_read_dword_ptr(void *ptr, uint32_t offset)
+{
+ uint32_t dword = read32(mei_mmap, offset);
+ memcpy(ptr, &dword, sizeof(dword));
+
+ if (debug) {
+ mei_dump(ptr, dword, offset, "READ");
+ }
+}
+
+static inline void mei_write_dword_ptr(void *ptr, uint32_t offset)
+{
+ uint32_t dword = 0;
+ memcpy(&dword, ptr, sizeof(dword));
+ write32(mei_mmap, offset, dword);
+
+ if (debug) {
+ mei_dump(ptr, dword, offset, "WRITE");
+ }
+}
+
+static inline void pci_read_dword_ptr(struct pci_dev *dev, void *ptr, uint32_t offset)
+{
+ uint32_t dword = pci_read_long(dev, offset);
+ memcpy(ptr, &dword, sizeof(dword));
+
+ if (debug) {
+ mei_dump(ptr, dword, offset, "PCI READ");
+ }
+}
+
+static inline void read_host_csr(struct mei_csr *csr)
+{
+ mei_read_dword_ptr(csr, MEI_H_CSR);
+}
+
+static inline void write_host_csr(struct mei_csr *csr)
+{
+ mei_write_dword_ptr(csr, MEI_H_CSR);
+}
+
+static inline void read_me_csr(struct mei_csr *csr)
+{
+ mei_read_dword_ptr(csr, MEI_ME_CSR_HA);
+}
+
+static inline void write_cb(uint32_t dword)
+{
+ write32(mei_mmap, MEI_H_CB_WW, dword);
+
+ if (debug) {
+ mei_dump(NULL, dword, MEI_H_CB_WW, "WRITE");
+ }
+}
+
+static inline uint32_t read_cb(void)
+{
+ uint32_t dword = read32(mei_mmap, MEI_ME_CB_RW);
+
+ if (debug) {
+ mei_dump(NULL, dword, MEI_ME_CB_RW, "READ");
+ }
+
+ return dword;
+}
+
+/* Wait for ME ready bit to be asserted */
+static int mei_wait_for_me_ready(void)
+{
+ struct mei_csr me;
+ unsigned try = ME_RETRY;
+
+ while (try--) {
+ read_me_csr(&me);
+ if (me.ready)
+ return 0;
+ usleep(ME_DELAY);
+ }
+
+ printf("ME: failed to become ready\n");
+ return -1;
+}
+
+void mei_reset(void)
+{
+ struct mei_csr host;
+
+ if (mei_wait_for_me_ready() < 0)
+ return;
+
+ /* Reset host and ME circular buffers for next message */
+ read_host_csr(&host);
+ host.reset = 1;
+ host.interrupt_generate = 1;
+ write_host_csr(&host);
+
+ if (mei_wait_for_me_ready() < 0)
+ return;
+
+ /* Re-init and indicate host is ready */
+ read_host_csr(&host);
+ host.interrupt_generate = 1;
+ host.ready = 1;
+ host.reset = 0;
+ write_host_csr(&host);
+}
+
+static int mei_send_msg(struct mei_header *mei, struct mkhi_header *mkhi,
+ void *req_data)
+{
+ struct mei_csr host;
+ unsigned ndata , n;
+ uint32_t *data;
+
+ /* Number of dwords to write, ignoring MKHI */
+ ndata = (mei->length) >> 2;
+
+ /* Pad non-dword aligned request message length */
+ if (mei->length & 3)
+ ndata++;
+ if (!ndata) {
+ printf("ME: request does not include MKHI\n");
+ return -1;
+ }
+ ndata++; /* Add MEI header */
+
+ /*
+ * Make sure there is still room left in the circular buffer.
+ * Reset the buffer pointers if the requested message will not fit.
+ */
+ read_host_csr(&host);
+ if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
+ printf("ME: circular buffer full, resetting...\n");
+ mei_reset();
+ read_host_csr(&host);
+ }
+
+ /*
+ * This implementation does not handle splitting large messages
+ * across multiple transactions. Ensure the requested length
+ * will fit in the available circular buffer depth.
+ */
+ if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
+ printf("ME: message (%u) too large for buffer (%u)\n",
+ ndata + 2, host.buffer_depth);
+ return -1;
+ }
+
+ /* Write MEI header */
+ mei_write_dword_ptr(mei, MEI_H_CB_WW);
+ ndata--;
+
+ /* Write MKHI header */
+ mei_write_dword_ptr(mkhi, MEI_H_CB_WW);
+ ndata--;
+
+ /* Write message data */
+ data = req_data;
+ for (n = 0; n < ndata; ++n)
+ write_cb(*data++);
+
+ /* Generate interrupt to the ME */
+ read_host_csr(&host);
+ host.interrupt_generate = 1;
+ write_host_csr(&host);
+
+ /* Make sure ME is ready after sending request data */
+ return mei_wait_for_me_ready();
+}
+
+static int mei_recv_msg(struct mei_header *mei, struct mkhi_header *mkhi,
+ void *rsp_data, uint32_t rsp_bytes)
+{
+ struct mei_header mei_rsp;
+ struct mkhi_header mkhi_rsp;
+ struct mei_csr me, host;
+ unsigned ndata, n;
+ unsigned expected;
+ uint32_t *data;
+
+ /* Total number of dwords to read from circular buffer */
+ expected = (rsp_bytes + sizeof(mei_rsp) + sizeof(mkhi_rsp)) >> 2;
+ if (rsp_bytes & 3)
+ expected++;
+
+ if (debug) {
+ printf("expected u32 = %d\n", expected);
+ }
+ /*
+ * The interrupt status bit does not appear to indicate that the
+ * message has actually been received. Instead we wait until the
+ * expected number of dwords are present in the circular buffer.
+ */
+ for (n = ME_RETRY; n; --n) {
+ read_me_csr(&me);
+ if ((me.buffer_write_ptr - me.buffer_read_ptr) >= expected)
+ //if (me.interrupt_generate && !me.interrupt_status)
+ //if (me.interrupt_status)
+ break;
+ usleep(ME_DELAY);
+ }
+ if (!n) {
+ printf("ME: timeout waiting for data: expected "
+ "%u, available %u\n", expected,
+ me.buffer_write_ptr - me.buffer_read_ptr);
+ return -1;
+ }
+ /* Read and verify MEI response header from the ME */
+ mei_read_dword_ptr(&mei_rsp, MEI_ME_CB_RW);
+ if (!mei_rsp.is_complete) {
+ printf("ME: response is not complete\n");
+ return -1;
+ }
+
+ /* Handle non-dword responses and expect at least MKHI header */
+ ndata = mei_rsp.length >> 2;
+ if (mei_rsp.length & 3)
+ ndata++;
+ if (ndata != (expected - 1)) { //XXX
+ printf("ME: response is missing data\n");
+ //return -1;
+ }
+
+ /* Read and verify MKHI response header from the ME */
+ mei_read_dword_ptr(&mkhi_rsp, MEI_ME_CB_RW);
+ if (!mkhi_rsp.is_response ||
+ mkhi->group_id != mkhi_rsp.group_id ||
+ mkhi->command != mkhi_rsp.command) {
+ printf("ME: invalid response, group %u ?= %u, "
+ "command %u ?= %u, is_response %u\n", mkhi->group_id,
+ mkhi_rsp.group_id, mkhi->command, mkhi_rsp.command,
+ mkhi_rsp.is_response);
+ //return -1;
+ }
+ ndata--; /* MKHI header has been read */
+
+ /* Make sure caller passed a buffer with enough space */
+ if (ndata != (rsp_bytes >> 2)) {
+ printf("ME: not enough room in response buffer: "
+ "%u != %u\n", ndata, rsp_bytes >> 2);
+ //return -1;
+ }
+
+ /* Read response data from the circular buffer */
+ data = rsp_data;
+ for (n = 0; n < ndata; ++n)
+ *data++ = read_cb();
+
+ /* Tell the ME that we have consumed the response */
+ read_host_csr(&host);
+ host.interrupt_status = 1;
+ host.interrupt_generate = 1;
+ write_host_csr(&host);
+
+ return mei_wait_for_me_ready();
+}
+
+static inline int mei_sendrecv(struct mei_header *mei, struct mkhi_header *mkhi,
+ void *req_data, void *rsp_data, uint32_t rsp_bytes)
+{
+ if (mei_send_msg(mei, mkhi, req_data) < 0)
+ return -1;
+ if (mei_recv_msg(mei, mkhi, rsp_data, rsp_bytes) < 0)
+ return -1;
+ return 0;
+}
+
+/* Send END OF POST message to the ME */
+/*
+static int mkhi_end_of_post(void)
+{
+ struct mkhi_header mkhi = {
+ .group_id = MKHI_GROUP_ID_GEN,
+ .command = MKHI_END_OF_POST,
+ };
+ struct mei_header mei = {
+ .is_complete = 1,
+ .host_address = MEI_HOST_ADDRESS,
+ .client_address = MEI_ADDRESS_MKHI,
+ .length = sizeof(mkhi),
+ };
+
+ if (mei_sendrecv(&mei, &mkhi, NULL, NULL, 0) < 0) {
+ printf("ME: END OF POST message failed\n");
+ return -1;
+ }
+
+ printf("ME: END OF POST message successful\n");
+ return 0;
+}
+*/
+
+/* Get ME firmware version */
+int mkhi_get_fw_version(void)
+{
+ uint32_t data = 0;
+ struct me_fw_version version = {0};
+
+ struct mkhi_header mkhi = {
+ .group_id = MKHI_GROUP_ID_GEN,
+ .command = GEN_GET_FW_VERSION,
+ .is_response = 0,
+ };
+
+ struct mei_header mei = {
+ .is_complete = 1,
+ .host_address = MEI_HOST_ADDRESS,
+ .client_address = MEI_ADDRESS_MKHI,
+ .length = sizeof(mkhi),
+ };
+
+#ifndef OLDARC
+ /* Send request and wait for response */
+ if (mei_sendrecv(&mei, &mkhi, &data, &version, sizeof(version) ) < 0) {
+ printf("ME: GET FW VERSION message failed\n");
+ return -1;
+ }
+ printf("ME: Firmware Version %u.%u.%u.%u (code) "
+ "%u.%u.%u.%u (recovery) "
+ "%u.%u.%u.%u (fitc)\n\n",
+ version.code_major, version.code_minor,
+ version.code_build_number, version.code_hot_fix,
+ version.recovery_major, version.recovery_minor,
+ version.recovery_build_number, version.recovery_hot_fix,
+ version.fitcmajor, version.fitcminor,
+ version.fitcbuildno, version.fitchotfix);
+#else
+ /* Send request and wait for response */
+ if (mei_sendrecv(&mei, &mkhi, &data, &version, 2*sizeof(uint32_t) ) < 0) {
+ printf("ME: GET FW VERSION message failed\n");
+ return -1;
+ }
+ printf("ME: Firmware Version %u.%u (code)\n\n"
+ version.code_major, version.code_minor);
+#endif
+ return 0;
+}
+
+static inline void print_cap(const char *name, int state)
+{
+ printf("ME Capability: %-30s : %s\n",
+ name, state ? "ON" : "OFF");
+}
+
+/* Get ME Firmware Capabilities */
+int mkhi_get_fwcaps(void)
+{
+ struct {
+ uint32_t rule_id;
+ uint32_t rule_len;
+
+ struct me_fwcaps cap;
+ } fwcaps;
+
+ fwcaps.rule_id = 0;
+ fwcaps.rule_len = 0;
+
+ struct mkhi_header mkhi = {
+ .group_id = MKHI_GROUP_ID_FWCAPS,
+ .command = MKHI_FWCAPS_GET_RULE,
+ .is_response = 0,
+ };
+ struct mei_header mei = {
+ .is_complete = 1,
+ .host_address = MEI_HOST_ADDRESS,
+ .client_address = MEI_ADDRESS_MKHI,
+ .length = sizeof(mkhi) + sizeof(fwcaps.rule_id),
+ };
+
+ /* Send request and wait for response */
+ if (mei_sendrecv(&mei, &mkhi, &fwcaps.rule_id, &fwcaps.cap, sizeof(fwcaps.cap)) < 0) {
+ printf("ME: GET FWCAPS message failed\n");
+ return -1;
+ }
+
+ print_cap("Full Network manageability ", fwcaps.cap.caps_sku.full_net);
+ print_cap("Regular Network manageability ", fwcaps.cap.caps_sku.std_net);
+ print_cap("Manageability ", fwcaps.cap.caps_sku.manageability);
+ print_cap("Small business technology ", fwcaps.cap.caps_sku.small_business);
+ print_cap("Level III manageability ", fwcaps.cap.caps_sku.l3manageability);
+ print_cap("IntelR Anti-Theft (AT) ", fwcaps.cap.caps_sku.intel_at);
+ print_cap("IntelR Capability Licensing Service (CLS) ",
+ fwcaps.cap.caps_sku.intel_cls);
+ print_cap("IntelR Power Sharing Technology (MPC) ",
+ fwcaps.cap.caps_sku.intel_mpc);
+ print_cap("ICC Over Clocking ", fwcaps.cap.caps_sku.icc_over_clocking);
+ print_cap("Protected Audio Video Path (PAVP) ", fwcaps.cap.caps_sku.pavp);
+ print_cap("IPV6 ", fwcaps.cap.caps_sku.ipv6);
+ print_cap("KVM Remote Control (KVM) ", fwcaps.cap.caps_sku.kvm);
+ print_cap("Outbreak Containment Heuristic (OCH) ", fwcaps.cap.caps_sku.och);
+ print_cap("Virtual LAN (VLAN) ", fwcaps.cap.caps_sku.vlan);
+ print_cap("TLS ", fwcaps.cap.caps_sku.tls);
+ print_cap("Wireless LAN (WLAN) ", fwcaps.cap.caps_sku.wlan);
+
+ return 0;
+}
+
+/* Tell ME to issue a global reset */
+uint32_t mkhi_global_reset(void)
+{
+ struct me_global_reset reset = {
+ .request_origin = GLOBAL_RESET_BIOS_POST,
+ .reset_type = CBM_RR_GLOBAL_RESET,
+ };
+ struct mkhi_header mkhi = {
+ .group_id = MKHI_GROUP_ID_CBM,
+ .command = MKHI_GLOBAL_RESET,
+ };
+ struct mei_header mei = {
+ .is_complete = 1,
+ .length = sizeof(mkhi) + sizeof(reset),
+ .host_address = MEI_HOST_ADDRESS,
+ .client_address = MEI_ADDRESS_MKHI,
+ };
+
+ printf("ME: Requesting global reset\n");
+
+ /* Send request and wait for response */
+ if (mei_sendrecv(&mei, &mkhi, &reset, NULL, 0) < 0) {
+ /* No response means reset will happen shortly... */
+ asm("hlt");
+ }
+
+ /* If the ME responded it rejected the reset request */
+ printf("ME: Global Reset failed\n");
+ return -1;
+}
+
+/* Tell ME thermal reporting parameters */
+/*
+void mkhi_thermal(void)
+{
+ struct me_thermal_reporting thermal = {
+ .polling_timeout = 2,
+ .smbus_ec_msglen = 1,
+ .smbus_ec_msgpec = 0,
+ .dimmnumber = 4,
+ };
+ struct mkhi_header mkhi = {
+ .group_id = MKHI_GROUP_ID_CBM,
+ .command = MKHI_THERMAL_REPORTING,
+ };
+ struct mei_header mei = {
+ .is_complete = 1,
+ .length = sizeof(mkhi) + sizeof(thermal),
+ .host_address = MEI_HOST_ADDRESS,
+ .client_address = MEI_ADDRESS_THERMAL,
+ };
+
+ printf("ME: Sending thermal reporting params\n");
+
+ mei_sendrecv(&mei, &mkhi, &thermal, NULL, 0);
+}
+*/
+
+/* Enable debug of internal ME memory */
+int mkhi_debug_me_memory(void *physaddr)
+{
+ uint32_t data = 0;
+
+ /* copy whole ME memory to a readable space */
+ struct me_debug_mem memory = {
+ .debug_phys = (uintptr_t)physaddr,
+ .debug_size = 0x2000000,
+ .me_phys = 0x20000000,
+ .me_size = 0x2000000,
+ };
+ struct mkhi_header mkhi = {
+ .group_id = MKHI_GROUP_ID_GEN,
+ .command = GEN_SET_DEBUG_MEM,
+ .is_response = 0,
+ };
+ struct mei_header mei = {
+ .is_complete = 1,
+ .length = sizeof(mkhi) + sizeof(memory),
+ .host_address = MEI_HOST_ADDRESS,
+ .client_address = MEI_ADDRESS_MKHI,
+ };
+
+ printf("ME: Debug memory to 0x%zx ...", (size_t)physaddr);
+ if (mei_sendrecv(&mei, &mkhi, &memory, &data, 0) < 0) {
+ printf("failed\n");
+ return -1;
+ } else {
+ printf("done\n");
+ }
+ return 0;
+}
+
+/* Prepare ME for MEI messages */
+uint32_t intel_mei_setup(struct pci_dev *dev)
+{
+ struct mei_csr host;
+ uint32_t reg32;
+ uint32_t pagerounded;
+
+ mei_base_address = dev->base_addr[0] & ~0xf;
+ pagerounded = mei_base_address & ~0xfff;
+ mei_mmap = map_physical(pagerounded, 0x2000) + mei_base_address - pagerounded;
+
+ /* Ensure Memory and Bus Master bits are set */
+ reg32 = pci_read_long(dev, PCI_COMMAND);
+ reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ pci_write_long(dev, PCI_COMMAND, reg32);
+
+ /* Clean up status for next message */
+ read_host_csr(&host);
+ host.interrupt_generate = 1;
+ host.ready = 1;
+ host.reset = 0;
+ write_host_csr(&host);
+
+ return 0;
+}
+
+/* Read the Extend register hash of ME firmware */
+int intel_me_extend_valid(struct pci_dev *dev)
+{
+ struct me_heres status;
+ uint32_t extend[8] = {0};
+ int i, count = 0;
+
+ pci_read_dword_ptr(dev, &status, PCI_ME_HERES);
+ if (!status.extend_feature_present) {
+ printf("ME: Extend Feature not present\n");
+ return -1;
+ }
+
+ if (!status.extend_reg_valid) {
+ printf("ME: Extend Register not valid\n");
+ return -1;
+ }
+
+ switch (status.extend_reg_algorithm) {
+ case PCI_ME_EXT_SHA1:
+ count = 5;
+ printf("ME: Extend SHA-1: ");
+ break;
+ case PCI_ME_EXT_SHA256:
+ count = 8;
+ printf("ME: Extend SHA-256: ");
+ break;
+ default:
+ printf("ME: Extend Algorithm %d unknown\n",
+ status.extend_reg_algorithm);
+ return -1;
+ }
+
+ for (i = 0; i < count; ++i) {
+ extend[i] = pci_read_long(dev, PCI_ME_HER(i));
+ printf("%08x", extend[i]);
+ }
+ printf("\n");
+
+ return 0;
+}
diff --git a/util/intelmetool/me.h b/util/intelmetool/me.h
new file mode 100644
index 0000000000..76ee245753
--- /dev/null
+++ b/util/intelmetool/me.h
@@ -0,0 +1,408 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * 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.
+ */
+
+#ifndef ME_H
+#define ME_H
+
+#include <inttypes.h>
+#include <pci/pci.h>
+
+#define ME_RETRY 100000 /* 1 second */
+#define ME_DELAY 10 /* 10 us */
+
+#pragma pack(1)
+
+/*
+ * Management Engine PCI registers
+ */
+
+#define PCI_ME_HFS 0x40
+#define ME_HFS_CWS_RESET 0
+#define ME_HFS_CWS_INIT 1
+#define ME_HFS_CWS_REC 2
+#define ME_HFS_CWS_NORMAL 5
+#define ME_HFS_CWS_WAIT 6
+#define ME_HFS_CWS_TRANS 7
+#define ME_HFS_CWS_INVALID 8
+#define ME_HFS_STATE_PREBOOT 0
+#define ME_HFS_STATE_M0_UMA 1
+#define ME_HFS_STATE_M3 4
+#define ME_HFS_STATE_M0 5
+#define ME_HFS_STATE_BRINGUP 6
+#define ME_HFS_STATE_ERROR 7
+#define ME_HFS_ERROR_NONE 0
+#define ME_HFS_ERROR_UNCAT 1
+#define ME_HFS_ERROR_IMAGE 3
+#define ME_HFS_ERROR_DEBUG 4
+#define ME_HFS_MODE_NORMAL 0
+#define ME_HFS_MODE_DEBUG 2
+#define ME_HFS_MODE_DIS 3
+#define ME_HFS_MODE_OVER_JMPR 4
+#define ME_HFS_MODE_OVER_MEI 5
+#define ME_HFS_BIOS_DRAM_ACK 1
+#define ME_HFS_ACK_NO_DID 0
+#define ME_HFS_ACK_RESET 1
+#define ME_HFS_ACK_PWR_CYCLE 2
+#define ME_HFS_ACK_S3 3
+#define ME_HFS_ACK_S4 4
+#define ME_HFS_ACK_S5 5
+#define ME_HFS_ACK_GBL_RESET 6
+#define ME_HFS_ACK_CONTINUE 7
+
+struct me_hfs {
+ uint32_t working_state: 4;
+ uint32_t mfg_mode: 1;
+ uint32_t fpt_bad: 1;
+ uint32_t operation_state: 3;
+ uint32_t fw_init_complete: 1;
+ uint32_t ft_bup_ld_flr: 1;
+ uint32_t update_in_progress: 1;
+ uint32_t error_code: 4;
+ uint32_t operation_mode: 4;
+ uint32_t reserved: 4;
+ uint32_t boot_options_present: 1;
+ uint32_t ack_data: 3;
+ uint32_t bios_msg_ack: 4;
+} __attribute__ ((packed));
+
+#define PCI_ME_UMA 0x44
+
+struct me_uma {
+ uint32_t size: 6;
+ uint32_t reserved_1: 10;
+ uint32_t valid: 1;
+ uint32_t reserved_0: 14;
+ uint32_t set_to_one: 1;
+} __attribute__ ((packed));
+
+#define PCI_ME_H_GS 0x4c
+#define ME_INIT_DONE 1
+#define ME_INIT_STATUS_SUCCESS 0
+#define ME_INIT_STATUS_NOMEM 1
+#define ME_INIT_STATUS_ERROR 2
+
+struct me_did {
+ uint32_t uma_base: 16;
+ uint32_t reserved: 8;
+ uint32_t status: 4;
+ uint32_t init_done: 4;
+} __attribute__ ((packed));
+
+#define PCI_ME_GMES 0x48
+#define ME_GMES_PHASE_ROM 0
+#define ME_GMES_PHASE_BUP 1
+#define ME_GMES_PHASE_UKERNEL 2
+#define ME_GMES_PHASE_POLICY 3
+#define ME_GMES_PHASE_MODULE 4
+#define ME_GMES_PHASE_UNKNOWN 5
+#define ME_GMES_PHASE_HOST 6
+
+struct me_gmes {
+ uint32_t bist_in_prog : 1;
+ uint32_t icc_prog_sts : 2;
+ uint32_t invoke_mebx : 1;
+ uint32_t cpu_replaced_sts : 1;
+ uint32_t mbp_rdy : 1;
+ uint32_t mfs_failure : 1;
+ uint32_t warm_rst_req_for_df : 1;
+ uint32_t cpu_replaced_valid : 1;
+ uint32_t reserved_1 : 2;
+ uint32_t fw_upd_ipu : 1;
+ uint32_t reserved_2 : 4;
+ uint32_t current_state: 8;
+ uint32_t current_pmevent: 4;
+ uint32_t progress_code: 4;
+} __attribute__ ((packed));
+
+#define PCI_ME_HERES 0xbc
+#define PCI_ME_EXT_SHA1 0x00
+#define PCI_ME_EXT_SHA256 0x02
+#define PCI_ME_HER(x) (0xc0+(4*(x)))
+
+struct me_heres {
+ uint32_t extend_reg_algorithm: 4;
+ uint32_t reserved: 26;
+ uint32_t extend_feature_present: 1;
+ uint32_t extend_reg_valid: 1;
+} __attribute__ ((packed));
+
+struct me_thermal_reporting {
+ uint32_t polling_timeout: 8;
+ uint32_t smbus_ec_msglen: 8;
+ uint32_t smbus_ec_msgpec: 8;
+ uint32_t dimmnumber: 8;
+} __attribute__ ((packed));
+
+/*
+ * Management Engine MEI registers
+ */
+
+#define MEI_H_CB_WW 0x00
+#define MEI_H_CSR 0x04
+#define MEI_ME_CB_RW 0x08
+#define MEI_ME_CSR_HA 0x0c
+
+struct mei_csr {
+ uint32_t interrupt_enable: 1;
+ uint32_t interrupt_status: 1;
+ uint32_t interrupt_generate: 1;
+ uint32_t ready: 1;
+ uint32_t reset: 1;
+ uint32_t reserved: 3;
+ uint32_t buffer_read_ptr: 8;
+ uint32_t buffer_write_ptr: 8;
+ uint32_t buffer_depth: 8;
+} __attribute__ ((packed));
+
+#define MEI_ADDRESS_HBM 0x00
+#define MEI_ADDRESS_CORE_WD 0x01
+#define MEI_ADDRESS_AMT 0x02
+#define MEI_ADDRESS_RESERVED 0x03
+#define MEI_ADDRESS_WDT 0x04
+#define MEI_ADDRESS_POLICY 0x05
+#define MEI_ADDRESS_PASSWORD 0x06
+#define MEI_ADDRESS_MKHI 0x07
+#define MEI_ADDRESS_ICC 0x08
+#define MEI_ADDRESS_THERMAL 0x09
+#define MEI_ADDRESS_SPI 0x0a
+
+#define MEI_HOST_ADDRESS 0
+
+struct mei_header {
+ uint32_t client_address: 8;
+ uint32_t host_address: 8;
+ uint32_t length: 9;
+ uint32_t reserved: 6;
+ uint32_t is_complete: 1;
+} __attribute__ ((packed));
+
+#define MKHI_GROUP_ID_CBM 0x00
+#define MKHI_GROUP_ID_PM 0x01
+#define MKHI_GROUP_ID_PWD 0x02
+#define MKHI_GROUP_ID_FWCAPS 0x03
+#define MKHI_GROUP_ID_APP 0x04
+#define MKHI_GROUP_ID_SPI 0x05
+#define MKHI_GROUP_ID_MDES 0x08
+#define MKHI_GROUP_ID_MAX 0x09
+#define MKHI_GROUP_ID_GEN 0xff
+
+#define MKHI_FWCAPS_GET_RULE 0x02
+#define MKHI_FWCAPS_SET_RULE 0x03
+#define MKHI_GLOBAL_RESET 0x0b
+
+#define GEN_GET_MKHI_VERSION 0x01
+#define GEN_GET_FW_VERSION 0x02
+#define GEN_UNCONFIG_NO_PWD 0x0d
+#define GEN_SET_DEBUG_MEM 0x11
+
+#define FWCAPS_ME_FWU_RULE 0x2e
+#define FWCAPS_OVERRIDE 0x14
+
+#define MKHI_THERMAL_REPORTING 0x00
+#define MKHI_GET_FW_VERSION 0x02
+#define MKHI_MDES_ENABLE 0x09
+#define MKHI_END_OF_POST 0x0c
+#define MKHI_FEATURE_OVERRIDE 0x14
+
+#define HBM_HOST_START_REQ_CMD 0x01
+#define HBM_HOST_STOP_REQ_CMD 0x02
+#define HBM_ME_STOP_REQ_CMD 0x03
+#define HBM_HOST_ENUM_REQ_CMD 0x04
+#define HBM_HOST_CLIENT_PROPERTIES_REQ_CMD 0x05
+#define HBM_CLIENT_CONNECT_REQ_CMD 0x06
+#define HBM_CLIENT_DISCONNECT_REQ_CMD 0x07
+
+struct mkhi_header {
+ uint32_t group_id: 8;
+ uint32_t command: 7;
+ uint32_t is_response: 1;
+ uint32_t reserved: 8;
+ uint32_t result: 8;
+} __attribute__ ((packed));
+
+struct me_fw_version {
+ uint16_t code_minor;
+ uint16_t code_major;
+ uint16_t code_build_number;
+ uint16_t code_hot_fix;
+ uint16_t recovery_minor;
+ uint16_t recovery_major;
+ uint16_t recovery_build_number;
+ uint16_t recovery_hot_fix;
+ uint16_t fitcminor;
+ uint16_t fitcmajor;
+ uint16_t fitcbuildno;
+ uint16_t fitchotfix;
+} __attribute__ ((packed));
+
+
+#define HECI_EOP_STATUS_SUCCESS 0x0
+#define HECI_EOP_PERFORM_GLOBAL_RESET 0x1
+
+#define CBM_RR_GLOBAL_RESET 0x01
+
+#define GLOBAL_RESET_BIOS_MRC 0x01
+#define GLOBAL_RESET_BIOS_POST 0x02
+#define GLOBAL_RESET_MEBX 0x03
+
+struct me_global_reset {
+ uint8_t request_origin;
+ uint8_t reset_type;
+} __attribute__ ((packed));
+
+typedef enum {
+ ME_NORMAL_BIOS_PATH,
+ ME_S3WAKE_BIOS_PATH,
+ ME_ERROR_BIOS_PATH,
+ ME_RECOVERY_BIOS_PATH,
+ ME_DISABLE_BIOS_PATH,
+ ME_FIRMWARE_UPDATE_BIOS_PATH,
+} me_bios_path;
+
+typedef struct {
+ uint32_t major_version : 16;
+ uint32_t minor_version : 16;
+ uint32_t hotfix_version : 16;
+ uint32_t build_version : 16;
+} __attribute__ ((packed)) mbp_fw_version_name;
+
+typedef struct {
+ uint8_t num_icc_profiles;
+ uint8_t icc_profile_soft_strap;
+ uint8_t icc_profile_index;
+ uint8_t reserved;
+ uint32_t register_lock_mask[3];
+} __attribute__ ((packed)) mbp_icc_profile;
+
+typedef struct {
+ uint32_t full_net : 1;
+ uint32_t std_net : 1;
+ uint32_t manageability : 1;
+ uint32_t small_business : 1;
+ uint32_t l3manageability : 1;
+ uint32_t intel_at : 1;
+ uint32_t intel_cls : 1;
+ uint32_t reserved : 3;
+ uint32_t intel_mpc : 1;
+ uint32_t icc_over_clocking : 1;
+ uint32_t pavp : 1;
+ uint32_t reserved_1 : 4;
+ uint32_t ipv6 : 1;
+ uint32_t kvm : 1;
+ uint32_t och : 1;
+ uint32_t vlan : 1;
+ uint32_t tls : 1;
+ uint32_t reserved_4 : 1;
+ uint32_t wlan : 1;
+ uint32_t reserved_5 : 8;
+} __attribute__ ((packed)) mefwcaps_sku;
+
+typedef struct {
+ uint16_t lock_state : 1;
+ uint16_t authenticate_module : 1;
+ uint16_t s3authentication : 1;
+ uint16_t flash_wear_out : 1;
+ uint16_t flash_variable_security : 1;
+ uint16_t wwan3gpresent : 1;
+ uint16_t wwan3goob : 1;
+ uint16_t reserved : 9;
+} __attribute__ ((packed)) tdt_state_flag;
+
+typedef struct {
+ uint8_t state;
+ uint8_t last_theft_trigger;
+ tdt_state_flag flags;
+} __attribute__ ((packed)) tdt_state_info;
+
+typedef struct {
+ uint32_t platform_target_usage_type : 4;
+ uint32_t platform_target_market_type : 2;
+ uint32_t super_sku : 1;
+ uint32_t reserved : 1;
+ uint32_t intel_me_fw_image_type : 4;
+ uint32_t platform_brand : 4;
+ uint32_t reserved_1 : 16;
+} __attribute__ ((packed)) platform_type_rule_data;
+
+typedef struct {
+ mefwcaps_sku fw_capabilities;
+ uint8_t available;
+} mbp_fw_caps;
+
+typedef struct {
+ uint16_t device_id;
+ uint16_t fuse_test_flags;
+ uint32_t umchid[4];
+} __attribute__ ((packed)) mbp_rom_bist_data;
+
+typedef struct {
+ uint32_t key[8];
+} mbp_platform_key;
+
+typedef struct {
+ platform_type_rule_data rule_data;
+ uint8_t available;
+} mbp_plat_type;
+
+typedef struct {
+ mbp_fw_version_name fw_version_name;
+ mbp_fw_caps fw_caps_sku;
+ mbp_rom_bist_data rom_bist_data;
+ mbp_platform_key platform_key;
+ mbp_plat_type fw_plat_type;
+ mbp_icc_profile icc_profile;
+ tdt_state_info at_state;
+ uint32_t mfsintegrity;
+} me_bios_payload;
+
+typedef struct {
+ uint32_t mbp_size : 8;
+ uint32_t num_entries : 8;
+ uint32_t rsvd : 16;
+} __attribute__ ((packed)) mbp_header;
+
+typedef struct {
+ uint32_t app_id : 8;
+ uint32_t item_id : 8;
+ uint32_t length : 8;
+ uint32_t rsvd : 8;
+} __attribute__ ((packed)) mbp_item_header;
+
+struct me_fwcaps {
+ uint32_t id;
+ uint8_t length;
+ mefwcaps_sku caps_sku;
+ uint8_t reserved[3];
+} __attribute__ ((packed));
+
+struct me_debug_mem {
+ uint32_t debug_phys;
+ uint32_t debug_size;
+ uint32_t me_phys;
+ uint32_t me_size;
+} __attribute__ ((packed));
+
+void intel_me_status(uint32_t hfs, uint32_t gmes);
+void mkhi_thermal(void);
+uint32_t intel_mei_setup(struct pci_dev *dev);
+void intel_mei_unmap(void);
+int mkhi_get_fwcaps(void);
+int mkhi_get_fw_version(void);
+int mkhi_debug_me_memory(void *addr);
+void mei_reset(void);
+int intel_me_extend_valid(struct pci_dev *dev);
+
+#endif
diff --git a/util/intelmetool/me_status.c b/util/intelmetool/me_status.c
new file mode 100644
index 0000000000..1de51f4f87
--- /dev/null
+++ b/util/intelmetool/me_status.c
@@ -0,0 +1,205 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include "me.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+/* HFS1[3:0] Current Working State Values */
+static const char *me_cws_values[] = {
+ [ME_HFS_CWS_RESET] = "Reset",
+ [ME_HFS_CWS_INIT] = "Initializing",
+ [ME_HFS_CWS_REC] = "Recovery",
+ [ME_HFS_CWS_NORMAL] = "Normal",
+ [ME_HFS_CWS_WAIT] = "Platform Disable Wait",
+ [ME_HFS_CWS_TRANS] = "OP State Transition",
+ [ME_HFS_CWS_INVALID] = "Invalid CPU Plugged In"
+};
+
+/* HFS1[8:6] Current Operation State Values */
+static const char *me_opstate_values[] = {
+ [ME_HFS_STATE_PREBOOT] = "Preboot",
+ [ME_HFS_STATE_M0_UMA] = "M0 with UMA",
+ [ME_HFS_STATE_M3] = "M3 without UMA",
+ [ME_HFS_STATE_M0] = "M0 without UMA",
+ [ME_HFS_STATE_BRINGUP] = "Bring up",
+ [ME_HFS_STATE_ERROR] = "M0 without UMA but with error"
+};
+
+/* HFS[19:16] Current Operation Mode Values */
+static const char *me_opmode_values[] = {
+ [ME_HFS_MODE_NORMAL] = "Normal",
+ [ME_HFS_MODE_DEBUG] = "Debug",
+ [ME_HFS_MODE_DIS] = "Soft Temporary Disable",
+ [ME_HFS_MODE_OVER_JMPR] = "Security Override via Jumper",
+ [ME_HFS_MODE_OVER_MEI] = "Security Override via MEI Message"
+};
+
+/* HFS[15:12] Error Code Values */
+static const char *me_error_values[] = {
+ [ME_HFS_ERROR_NONE] = "No Error",
+ [ME_HFS_ERROR_UNCAT] = "Uncategorized Failure",
+ [ME_HFS_ERROR_IMAGE] = "Image Failure",
+ [ME_HFS_ERROR_DEBUG] = "Debug Failure"
+};
+
+/* GMES[31:28] ME Progress Code */
+static const char *me_progress_values[] = {
+ [ME_GMES_PHASE_ROM] = "ROM Phase",
+ [ME_GMES_PHASE_BUP] = "BUP Phase",
+ [ME_GMES_PHASE_UKERNEL] = "uKernel Phase",
+ [ME_GMES_PHASE_POLICY] = "Policy Module",
+ [ME_GMES_PHASE_MODULE] = "Module Loading",
+ [ME_GMES_PHASE_UNKNOWN] = "Unknown",
+ [ME_GMES_PHASE_HOST] = "Host Communication"
+};
+
+/* GMES[27:24] Power Management Event */
+static const char *me_pmevent_values[] = {
+ [0x00] = "Clean Moff->Mx wake",
+ [0x01] = "Moff->Mx wake after an error",
+ [0x02] = "Clean global reset",
+ [0x03] = "Global reset after an error",
+ [0x04] = "Clean Intel ME reset",
+ [0x05] = "Intel ME reset due to exception",
+ [0x06] = "Pseudo-global reset",
+ [0x07] = "S0/M0->Sx/M3",
+ [0x08] = "Sx/M3->S0/M0",
+ [0x09] = "Non-power cycle reset",
+ [0x0a] = "Power cycle reset through M3",
+ [0x0b] = "Power cycle reset through Moff",
+ [0x0c] = "Sx/Mx->Sx/Moff"
+};
+
+/* Progress Code 0 states */
+static const char *me_progress_rom_values[] = {
+ [0x00] = "BEGIN",
+ [0x06] = "DISABLE"
+};
+
+/* Progress Code 1 states */
+static const char *me_progress_bup_values[] = {
+ [0x00] = "Initialization starts",
+ [0x01] = "Disable the host wake event",
+ [0x04] = "Flow determination start process",
+ [0x08] = "Error reading/matching the VSCC table in the descriptor",
+ [0x0a] = "Check to see if straps say ME DISABLED",
+ [0x0b] = "Timeout waiting for PWROK",
+ [0x0d] = "Possibly handle BUP manufacturing override strap",
+ [0x11] = "Bringup in M3",
+ [0x12] = "Bringup in M0",
+ [0x13] = "Flow detection error",
+ [0x15] = "M3 clock switching error",
+ [0x18] = "M3 kernel load",
+ [0x1c] = "T34 missing - cannot program ICC",
+ [0x1f] = "Waiting for DID BIOS message",
+ [0x20] = "Waiting for DID BIOS message failure",
+ [0x21] = "DID reported an error",
+ [0x22] = "Enabling UMA",
+ [0x23] = "Enabling UMA error",
+ [0x24] = "Sending DID Ack to BIOS",
+ [0x25] = "Sending DID Ack to BIOS error",
+ [0x26] = "Switching clocks in M0",
+ [0x27] = "Switching clocks in M0 error",
+ [0x28] = "ME in temp disable",
+ [0x32] = "M0 kernel load",
+};
+
+/* Progress Code 3 states */
+static const char *me_progress_policy_values[] = {
+ [0x00] = "Entery into Policy Module",
+ [0x03] = "Received S3 entry",
+ [0x04] = "Received S4 entry",
+ [0x05] = "Received S5 entry",
+ [0x06] = "Received UPD entry",
+ [0x07] = "Received PCR entry",
+ [0x08] = "Received NPCR entry",
+ [0x09] = "Received host wake",
+ [0x0a] = "Received AC<>DC switch",
+ [0x0b] = "Received DRAM Init Done",
+ [0x0c] = "VSCC Data not found for flash device",
+ [0x0d] = "VSCC Table is not valid",
+ [0x0e] = "Flash Partition Boundary is outside address space",
+ [0x0f] = "ME cannot access the chipset descriptor region",
+ [0x10] = "Required VSCC values for flash parts do not match",
+};
+
+void intel_me_status(uint32_t hfs, uint32_t gmes)
+{
+ /* Check Current States */
+ printf("ME: FW Partition Table : %s\n",
+ ((hfs & 0x20) >> 5) ? "BAD" : "OK");
+ printf("ME: Bringup Loader Failure : %s\n",
+ ((hfs & 0x400) >> 10) ? "YES" : "NO");
+ printf("ME: Firmware Init Complete : %s\n",
+ ((hfs & 0x200) >> 9) ? "YES" : "NO");
+ printf("ME: Manufacturing Mode : %s\n",
+ ((hfs & 0x10) >> 4) ? "YES" : "NO");
+ printf("ME: Boot Options Present : %s\n",
+ ((hfs & 0x1000000) >> 24) ? "YES" : "NO");
+ printf("ME: Update In Progress : %s\n",
+ ((hfs & 0x800) >> 11) ? "YES" : "NO");
+ printf("ME: Current Working State : %s\n",
+ me_cws_values[hfs & 0xf]);
+ printf("ME: Current Operation State : %s\n",
+ me_opstate_values[(hfs & 0x1c0) >> 6]);
+ printf("ME: Current Operation Mode : %s\n",
+ me_opmode_values[(hfs & 0xf0000) >> 16]);
+ printf("ME: Error Code : %s\n",
+ me_error_values[(hfs & 0xf000) >> 12]);
+ printf("ME: Progress Phase : %s\n",
+ me_progress_values[(gmes & 0xf0000000) >> 28]);
+ printf("ME: Power Management Event : %s\n",
+ me_pmevent_values[(gmes & 0xf000000) >> 24]);
+
+ printf("ME: Progress Phase State : ");
+ switch ((gmes & 0xf0000000) >> 28) {
+ case ME_GMES_PHASE_ROM: /* ROM Phase */
+ printf("%s",
+ me_progress_rom_values[(gmes & 0xff0000) >> 16]);
+ break;
+
+ case ME_GMES_PHASE_BUP: /* Bringup Phase */
+ if ((gmes & 0xff0000) >> 16 < ARRAY_SIZE(me_progress_bup_values)
+ && me_progress_bup_values[(gmes & 0xff0000) >> 16])
+ printf("%s",
+ me_progress_bup_values[(gmes & 0xff0000) >> 16]);
+ else
+ printf("0x%02x", (gmes & 0xff0000) >> 16);
+ break;
+
+ case ME_GMES_PHASE_POLICY: /* Policy Module Phase */
+ if ((gmes & 0xff0000) >> 16 < ARRAY_SIZE(me_progress_policy_values)
+ && me_progress_policy_values[(gmes & 0xff0000) >> 16])
+ printf("%s",
+ me_progress_policy_values[(gmes & 0xff0000) >> 16]);
+ else
+ printf("0x%02x", (gmes & 0xff0000) >> 16);
+ break;
+
+ case ME_GMES_PHASE_HOST: /* Host Communication Phase */
+ if (!((gmes & 0xff0000) >> 16))
+ printf("Host communication established");
+ else
+ printf("0x%02x", (gmes & 0xff0000) >> 16);
+ break;
+
+ default:
+ printf("Unknown 0x%02x", (gmes & 0xff0000) >> 16);
+ }
+ printf("\n");
+}
diff --git a/util/intelmetool/mmap.c b/util/intelmetool/mmap.c
new file mode 100644
index 0000000000..da36eaac08
--- /dev/null
+++ b/util/intelmetool/mmap.c
@@ -0,0 +1,58 @@
+/* intelmetool
+ *
+ * Copyright (C) 2013-2015 Damien Zammit <damien@zamaudio.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or any later version.
+ *
+ * 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.
+ */
+
+#include "mmap.h"
+#include <errno.h>
+
+#ifndef __DARWIN__
+int fd_mem;
+
+void *map_physical_exact(uint64_t phys_addr, uint64_t mapto, size_t len) {
+ void *virt_addr;
+ int err;
+
+ virt_addr = mmap((void*)mapto, len, PROT_WRITE | PROT_READ,
+ MAP_SHARED | MAP_FIXED, fd_mem, (off_t) phys_addr);
+
+ if (virt_addr == MAP_FAILED) {
+ err = errno;
+ printf("Error mapping physical memory 0x%016" PRIx64 "[0x%zx] ERRNO=%d\n",
+ phys_addr, len, err);
+ return NULL;
+ }
+
+ return virt_addr;
+}
+
+void *map_physical(uint64_t phys_addr, size_t len) {
+ void *virt_addr;
+ int err;
+
+ virt_addr = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, fd_mem, (off_t) phys_addr);
+
+ if (virt_addr == MAP_FAILED) {
+ err = errno;
+ printf("Error mapping physical memory 0x%016" PRIx64 "[0x%zx] ERRNO=%d\n",
+ phys_addr, len, err);
+ return NULL;
+ }
+
+ return virt_addr;
+}
+
+void unmap_physical(void *virt_addr, size_t len) {
+ munmap(virt_addr, len);
+}
+#endif
diff --git a/util/intelmetool/mmap.h b/util/intelmetool/mmap.h
new file mode 100644
index 0000000000..109ceff498
--- /dev/null
+++ b/util/intelmetool/mmap.h
@@ -0,0 +1,27 @@
+/* intelmetool
+ *
+ * Copyright (C) 2013-2015 Damien Zammit <damien@zamaudio.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or any later version.
+ *
+ * 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.
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <stdio.h>
+
+#ifndef __DARWIN__
+extern int fd_mem;
+extern void *map_physical(uint64_t phys_addr, size_t len);
+extern void unmap_physical(void *virt_addr, size_t len);
+extern void *map_physical_exact(uint64_t phys_addr, uint64_t mapto, size_t len);
+#endif