[coreboot-gerrit] Patch set updated for coreboot: util/intelmetool: Add intelmetool from Damien Zammit

Philipp Deppenwiese (zaolin.daisuki@googlemail.com) gerrit at coreboot.org
Fri Mar 18 01:04:05 CET 2016


Philipp Deppenwiese (zaolin.daisuki at googlemail.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14136

-gerrit

commit e9ee40ba408d89c8b3784aaff29023e31b276ce4
Author: Philipp Deppenwiese <zaolin at das-labor.org>
Date:   Fri Mar 18 00:52:54 2016 +0100

    util/intelmetool: Add intelmetool from Damien Zammit
    
    Original source code can be found under following link:
    https://github.com/zamaudio/intelmetool.git
    
    Change-Id: I0eb17833a21eb04cf9245a7312289a4102bec1a9
    Signed-off-by: Philipp Deppenwiese <zaolin at das-labor.org>
---
 util/intelmetool/Makefile      |  88 ++++++
 util/intelmetool/intelmetool.c | 312 ++++++++++++++++++++
 util/intelmetool/intelmetool.h | 238 +++++++++++++++
 util/intelmetool/me.c          | 638 +++++++++++++++++++++++++++++++++++++++++
 util/intelmetool/me.h          | 409 ++++++++++++++++++++++++++
 util/intelmetool/me_status.c   | 205 +++++++++++++
 util/intelmetool/mmap.c        |  59 ++++
 util/intelmetool/mmap.h        |  23 ++
 8 files changed, 1972 insertions(+)

diff --git a/util/intelmetool/Makefile b/util/intelmetool/Makefile
new file mode 100644
index 0000000..417c42a
--- /dev/null
+++ b/util/intelmetool/Makefile
@@ -0,0 +1,88 @@
+# intelmetool
+
+# Copyright (C) 2013-2015 Damien Zammit <damien at 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
+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"; \
+		printf "See README for more information.\n\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 0000000..b81d6ce
--- /dev/null
+++ b/util/intelmetool/intelmetool.c
@@ -0,0 +1,312 @@
+/* intelmetool  Dump interesting things about Management Engine even if hidden
+ * Copyright (C) 2014  Damien Zammit <damien at 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 <pci/pci.h>
+#include <sys/io.h>
+#include <stdlib.h>
+#include "me.h"
+#include "mmap.h"
+#include "intelmetool.h"
+
+extern int fd_mem;
+#define FD2 0x3428
+
+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");
+}
+
+void zeroit(uint8_t *phys, uint32_t size)
+{
+	uint32_t i;
+	for (i = 0; i < size; i++) {
+		*((uint8_t *) (phys + i)) = 0x00;
+	}
+}
+
+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);
+}
+
+int main(void)
+{
+	struct pci_access *pacc;
+	struct pci_dev *dev;
+	struct pci_dev *sb;
+	uint32_t stat, stat2;
+	char namebuf[1024], *name;
+	int size = 0x4000;
+	if (iopl(3)) {
+		perror("iopl");
+		printf("You need to be root\n");
+		exit(1);
+	}
+
+        if ((fd_mem = open("/dev/mem", O_RDWR)) < 0) {
+                perror("Can not open /dev/mem");
+                exit(1);
+        }
+
+	volatile uint8_t *rcba;
+	uint32_t rcba_phys;
+	uint32_t fd2;
+	uint8_t me;
+
+	pacc = pci_alloc();
+	pacc->method = PCI_ACCESS_I386_TYPE1;
+	pci_init(pacc);
+	pci_scan_bus(pacc);
+	me = ME_FOUND_NOTHING;
+	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_NO_ME(dev->device_id)) {
+				me = ME_NOT_PRESENT;
+				break;
+			}
+			if (PCI_DEV_HAS_ME_DISABLE(dev->device_id)) {
+				me = ME_PRESENT_CAN_DISABLE;
+				break;
+			}
+			if (PCI_DEV_HAS_ME_DIFFICULT(dev->device_id)) {
+				me = ME_PRESENT_CANNOT_DISABLE;
+				break;
+			}
+			if (PCI_DEV_CAN_DISABLE_ME_IF_PRESENT(dev->device_id)) {
+				me = ME_CAN_DISABLE_IF_PRESENT;
+				break;
+			}
+			if (PCI_DEV_ME_NOT_SURE(dev->device_id)) {
+				me = ME_FOUND_SOMETHING_NOT_SURE;
+				break;
+			}
+		}
+	}
+
+	switch (me) {
+		case ME_FOUND_NOTHING:
+			printf("Hardware unsupported by intelmetool, exiting\n");
+			pci_cleanup(pacc);
+			exit(ME_FOUND_NOTHING);
+			break;
+		case ME_FOUND_SOMETHING_NOT_SURE:
+			printf("Found `%s`. Not sure whether you have ME hardware, exiting\n", name);
+			pci_cleanup(pacc);
+			exit(ME_FOUND_SOMETHING_NOT_SURE);
+			break;
+		case ME_NOT_PRESENT:
+			printf("ME is not present on your board because we found a `%s`, you are safe, exiting\n", name);
+			pci_cleanup(pacc);
+			exit(ME_NOT_PRESENT);
+			break;
+		case ME_CAN_DISABLE_IF_PRESENT:
+			printf("Not sure if ME hardware is present because you have a `%s`, but it is possible to disable it if you do, continuing...\n", name);
+			break;
+		case ME_PRESENT_CANNOT_DISABLE:
+			printf("Bad news, you have a `%s` so you have ME hardware on board and it is very difficult to remove, continuing...\n", name);
+			break;
+		case ME_PRESENT_CAN_DISABLE:
+			printf("Good news, you have a `%s` so ME is present but can be disabled, continuing...\n", name);
+			break;
+		default:
+			printf("Something horrible happened, exiting\n");
+			pci_cleanup(pacc);
+			exit(1);
+			break;
+	}
+
+
+	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);
+		exit(1);
+	}
+	pci_fill_info(sb, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_CLASS);
+
+	/* Enable MEI */
+	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);
+
+	pacc = pci_alloc();
+	pacc->method = PCI_ACCESS_I386_TYPE1;
+	pci_init(pacc);
+	pci_scan_bus(pacc);
+	me = 0;
+	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) {
+			switch (dev->device_id) {
+				case 0x1C3A:  /* Cougar Point */
+				case 0x1CBA:  /* Panther Point */
+				case 0x1D3A:  /* C600/X79 Patsburg */
+				case 0x1DBA:  /* Panther Point */
+				case 0x1E3A:  /* Panther Point */
+				case 0x2364:  /* Cave Creek */
+				case 0x28B4:  /* Bearlake */
+				case 0x28C4:  /* Bearlake */
+				case 0x28D4:  /* Bearlake */
+				case 0x28E4:  /* Bearlake */
+				case 0x28F4:  /* Bearlake */
+				case 0x2974:  /* 82946GZ/GL */
+				case 0x2984:  /* 82G35 Express */
+				case 0x2994:  /* 82Q963/Q965 */
+				case 0x29A4:  /* 82P965/G965 */
+				case 0x29B4:  /* 82Q35 Express */
+				case 0x29C4:  /* 82G33/G31/P35/P31 Express */
+				case 0x29D4:  /* 82Q33 Express */
+				case 0x29E4:  /* 82X38/X48 Express */
+				case 0x29F4:  /* 3200/3210 Server */
+				case 0x2A04:  /* Mobile PM965/GM965 */
+				case 0x2A14:  /* Mobile GME965/GLE960 */
+				case 0x2A44:  /* Cantiga */
+				case 0x2a50:  /* Cantiga */
+				case 0x2A54:  /* Cantiga */
+				case 0x2A64:  /* Cantiga */
+				case 0x2A74:  /* Cantiga */
+				case 0x2E04:  /* Eaglelake */
+				case 0x2E14:  /* Eaglelake */
+				case 0x2E24:  /* Eaglelake */
+				case 0x2E34:  /* Eaglelake */
+				case 0x3B64:  /* Calpella */
+				case 0x3B65:  /* Calpella */
+				case 0x8C3A:  /* Lynx Point H */
+				case 0x8CBA:  /* Lynx Point H Refresh */
+				case 0x8D3A:  /* Lynx Point - Wellsburg */
+				case 0x9C3A:  /* Lynx Point LP */
+				case 0x9CBA:  /* Wildcat Point LP */
+				case 0x9CBB:  /* Wildcat Point LP 2 */
+					me = 1;
+					break;
+				default:
+					me = 0;
+					break;
+			}
+		}
+		if (me) break;
+	}
+	if (me == 0) {
+		printf("MEI device not found, huh?\n");
+		if (fd2 & 0x2) {
+			printf("Re-hiding MEI device...");
+			fd2 = *(uint32_t *)(rcba + FD2);
+			*(uint32_t *)(rcba + FD2) = fd2 | 0x2;
+			printf("done\n");
+		}
+		printf ("exiting\n");
+		pci_cleanup(pacc);
+		munmap((void*)rcba, size);
+		return 0;
+	}
+
+	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 seems okay on this board\n");
+	} else {
+		printf("ME has a broken implementation on your board with this BIOS\n");
+	}
+
+	intel_mei_setup(dev);
+	udelay(1000);
+	mei_reset();
+	udelay(10000);
+	mkhi_get_fw_version();
+	udelay(10000);
+	mei_reset();
+	udelay(10000);
+	mkhi_get_fwcaps();
+	udelay(10000);
+
+	/* 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.
+	 */
+/*
+	uint32_t me_clone = 0x60000000;
+	volatile 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();
+	udelay(10000);
+	int err = mkhi_debug_me_memory(me_clone);
+
+	if (!err) {
+		printf("Wait a second...");
+		udelay(30000);
+		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);
+	}
+*/
+	intel_mei_unmap();
+
+	pci_cleanup(pacc);
+
+	if (fd2 & 0x2) {
+		printf("Re-hiding MEI device...");
+		fd2 = *(uint32_t *)(rcba + FD2);
+		*(uint32_t *)(rcba + FD2) = fd2 | 0x2;
+		printf("done, ");
+	}
+	printf("exiting\n");
+	munmap((void*)rcba, size);
+	return 0;
+}
diff --git a/util/intelmetool/intelmetool.h b/util/intelmetool/intelmetool.h
new file mode 100644
index 0000000..a0088b9
--- /dev/null
+++ b/util/intelmetool/intelmetool.h
@@ -0,0 +1,238 @@
+/*
+ * 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
+
+// If any of the following pci device IDs are found,
+// the heading they fall under is the corresponding result.
+
+// Chipset does not have ME
+#define PCI_DEVICE_ID_INTEL_82810		0x7120
+#define PCI_DEVICE_ID_INTEL_82810_DC		0x7122
+#define PCI_DEVICE_ID_INTEL_82810E_DC		0x7124
+#define PCI_DEVICE_ID_INTEL_82830M		0x3575
+#define PCI_DEVICE_ID_INTEL_82845		0x1a30
+#define PCI_DEVICE_ID_INTEL_82865		0x2570
+#define PCI_DEVICE_ID_INTEL_82915		0x2580
+#define PCI_DEVICE_ID_INTEL_82945P		0x2770
+#define PCI_DEVICE_ID_INTEL_82945GM		0x27a0
+#define PCI_DEVICE_ID_INTEL_82945GSE		0x27ac
+#define PCI_DEVICE_ID_INTEL_82X58		0x3405
+#define PCI_DEVICE_ID_INTEL_ATOM_DXXX		0xa000
+#define PCI_DEVICE_ID_INTEL_I63XX		0x2670
+#define PCI_DEVICE_ID_INTEL_I5000X		0x25c0
+#define PCI_DEVICE_ID_INTEL_I5000Z		0x25d0
+#define PCI_DEVICE_ID_INTEL_I5000V		0x25d4
+#define PCI_DEVICE_ID_INTEL_I5000P		0x25d8
+#define PCI_DEVICE_ID_INTEL_82443LX		0x7180
+#define PCI_DEVICE_ID_INTEL_82443BX		0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_NO_AGP	0x7192
+#define PCI_DEVICE_ID_INTEL_82371XX		0x7110
+#define PCI_DEVICE_ID_INTEL_ICH			0x2410
+#define PCI_DEVICE_ID_INTEL_ICH0		0x2420
+#define PCI_DEVICE_ID_INTEL_ICH2		0x2440
+#define PCI_DEVICE_ID_INTEL_ICH4		0x24c0
+#define PCI_DEVICE_ID_INTEL_ICH4M		0x24cc
+#define PCI_DEVICE_ID_INTEL_ICH5		0x24d0
+#define PCI_DEVICE_ID_INTEL_ICH6		0x2640
+#define PCI_DEVICE_ID_INTEL_ICH7DH		0x27b0
+#define PCI_DEVICE_ID_INTEL_ICH7		0x27b8
+#define PCI_DEVICE_ID_INTEL_ICH7M		0x27b9
+#define PCI_DEVICE_ID_INTEL_ICH7MDH		0x27bd
+#define PCI_DEVICE_ID_INTEL_NM10		0x27bc
+
+#define PCI_DEV_NO_ME(x) ( \
+	( (x) == PCI_DEVICE_ID_INTEL_82810	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82810_DC	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82810E_DC	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82830M	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82845	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82865	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82915	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82945P	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82945GM	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82945GSE	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82X58	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ATOM_DXXX	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_I63XX	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_I5000X	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_I5000Z	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_I5000V	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_I5000P	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82443LX	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82443BX	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82443BX_NO_AGP) || \
+	( (x) == PCI_DEVICE_ID_INTEL_82371XX	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH0	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH2	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH4	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH4M	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH5	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH6	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH7DH	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH7	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH7M	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_ICH7MDH	) || \
+	( (x) == PCI_DEVICE_ID_INTEL_NM10	))
+
+// 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_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_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))
diff --git a/util/intelmetool/me.c b/util/intelmetool/me.c
new file mode 100644
index 0000000..709abae
--- /dev/null
+++ b/util/intelmetool/me.c
@@ -0,0 +1,638 @@
+/*
+ * 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 "me.h"
+#include "mmap.h"
+
+#define read32(addr, off) ( *((uint32_t *) (addr + off)) )
+#define write32(addr, off, val) ( *((uint32_t *) (addr + off)) = val)
+
+// FIXME: define this for old firmware only
+//#define OLDARC 1
+
+void udelay(uint32_t usecs)
+{
+	uint32_t i;
+	for(i = 0; i < usecs; i++)
+		inb(0x80);
+}
+
+/* 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;
+
+#if 1
+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;
+	}
+}
+#else
+# define mei_dump(ptr,dword,offset,type) do {} while (0)
+#endif
+
+/*
+ * 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));
+	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);
+	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));
+	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);
+	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);
+	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;
+		udelay(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++;
+
+	//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;
+		udelay(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",
+	       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"
+	       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;
+}
+
+void intel_mei_unmap(void)
+{
+	//munmap(mei_mmap, 0x2000);
+}
+
+/* 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 0000000..2778266
--- /dev/null
+++ b/util/intelmetool/me.h
@@ -0,0 +1,409 @@
+/*
+ * 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);
+void udelay(uint32_t usecs);
+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 0000000..1de51f4
--- /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 0000000..50b6d85
--- /dev/null
+++ b/util/intelmetool/mmap.c
@@ -0,0 +1,59 @@
+# intelmetool
+
+# Copyright (C) 2013-2015 Damien Zammit <damien at 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>
+
+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);
+}
diff --git a/util/intelmetool/mmap.h b/util/intelmetool/mmap.h
new file mode 100644
index 0000000..53bcb1c
--- /dev/null
+++ b/util/intelmetool/mmap.h
@@ -0,0 +1,23 @@
+# intelmetool
+
+# Copyright (C) 2013-2015 Damien Zammit <damien at 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>
+
+extern int fd_mem;
+void *map_physical(uint64_t phys_addr, size_t len);
+void unmap_physical(void *virt_addr, size_t len);



More information about the coreboot-gerrit mailing list