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>
This commit is contained in:
Philipp Deppenwiese 2016-03-18 00:52:54 +01:00 committed by Martin Roth
parent 77e351d9d1
commit d8fe4431ec
8 changed files with 2070 additions and 0 deletions

87
util/intelmetool/Makefile Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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))

640
util/intelmetool/me.c Normal file
View File

@ -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;
}

408
util/intelmetool/me.h Normal file
View File

@ -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

View File

@ -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");
}

58
util/intelmetool/mmap.c Normal file
View File

@ -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

27
util/intelmetool/mmap.h Normal file
View File

@ -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