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:
parent
77e351d9d1
commit
d8fe4431ec
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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))
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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");
|
||||
}
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue