[coreboot] New patch to review for coreboot: e5b0852 ELOG: Add support for SMM and kernel GSMI driver

Stefan Reinauer (stefan.reinauer@coreboot.org) gerrit at coreboot.org
Tue Jul 24 00:31:26 CEST 2012


Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1316

-gerrit

commit e5b0852cb546d30252dbec1f323f2ce3292a6c89
Author: Duncan Laurie <dlaurie at chromium.org>
Date:   Sat Jun 23 16:48:38 2012 -0700

    ELOG: Add support for SMM and kernel GSMI driver
    
    The linux kernel contains an SMI driver that was written by
    me (Duncan) and upstreamed a couple years ago called GSMI.
    This driver will format a parameter buffer and pass pointers
    to this parameter buffer to the SMI handler.  It uses this to
    generate events for kernel shutdown reasons:  Clean, Panic, Oops,
    etc.
    
    This function expects to be passed pointers into the SMM state
    save area that correspond to the prameter buffer and the return
    code, which are typically EAX and EBX.
    
    The format of the parameter buffer is defined in the kernel
    driver so we implement the same interface here in order to be
    compatible.
    
    GSMI_CMD_HANDSHAKE: this is an early call that it does to try
    and detect what kind of BIOS is running.
    
    GSMI_CMD_SET_EVENT_LOG: this contains a parameter buffer that
    has event type and data.  The kernel-specific events are
    translated here and raw events are passed through as well which
    allows any run-time event to be added for testing.
    
    GSMI_CMD_CLEAR_EVENT_LOG: this command clears the event log.
    
    First the gsmi driver must be enabled in the kernel with
    CONFIG_GOOGLE_GSMI and then events can be added via sysfs
    and events are automatically generated for various kernel
    shutdown reasons.
    
    These can be seen in the event log as the 'Kernel Event' type:
    
    169 | 2012-06-23 15:03:04 | Kernl Event | Clean Shutdown
    181 | 2012-06-23 16:26:32 | Kernl Event | Oops
    181 | 2012-06-23 16:26:32 | Kernl Event | Panic
    
    Change-Id: Ic0a3916401f0d9811e4aa8b2c560657dccc920c1
    Signed-off-by: Duncan Laurie <dlaurie at chromium.org>
---
 src/drivers/elog/Kconfig      |    9 +++
 src/drivers/elog/Makefile.inc |    2 +
 src/drivers/elog/gsmi.c       |  117 +++++++++++++++++++++++++++++++++++++++++
 src/include/elog.h            |    4 ++
 4 files changed, 132 insertions(+), 0 deletions(-)

diff --git a/src/drivers/elog/Kconfig b/src/drivers/elog/Kconfig
index 867416c..7912ab8 100644
--- a/src/drivers/elog/Kconfig
+++ b/src/drivers/elog/Kconfig
@@ -68,6 +68,15 @@ config ELOG_SHRINK_SIZE
 
 endif
 
+config ELOG_GSMI
+	depends on ELOG && SPI_FLASH_SMM && SMM_TSEG
+	bool "SMI interface to write and clear event log"
+	default n
+	help
+	  This interface is compatible with the linux kernel driver
+	  available with CONFIG_GOOGLE_GSMI and can be used to write
+	  kernel reset/shutdown messages to the event log.
+
 config ELOG_BOOT_COUNT
 	depends on ELOG
 	bool "Maintain a monotonic boot number in CMOS"
diff --git a/src/drivers/elog/Makefile.inc b/src/drivers/elog/Makefile.inc
index 32509c8..79a7cc0 100644
--- a/src/drivers/elog/Makefile.inc
+++ b/src/drivers/elog/Makefile.inc
@@ -1,4 +1,6 @@
 ramstage-$(CONFIG_ELOG) += elog.c
 
+smm-$(CONFIG_ELOG_GSMI) += elog.c gsmi.c
+
 romstage-$(CONFIG_ELOG_BOOT_COUNT) += boot_count.c
 ramstage-$(CONFIG_ELOG_BOOT_COUNT) += boot_count.c
diff --git a/src/drivers/elog/gsmi.c b/src/drivers/elog/gsmi.c
new file mode 100644
index 0000000..dac1af4
--- /dev/null
+++ b/src/drivers/elog/gsmi.c
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 The ChromiumOS 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <cpu/x86/smm.h>
+#include <elog.h>
+
+#define GSMI_RET_SUCCESS		0x00
+#define GSMI_RET_INVALID_PARAMETER	0x82
+#define GSMI_RET_UNSUPPORTED		0x83
+
+#define GSMI_CMD_SET_EVENT_LOG		0x08
+#define GSMI_CMD_CLEAR_EVENT_LOG	0x09
+#define GSMI_CMD_HANDSHAKE_TYPE		0xc1
+
+#define GSMI_HANDSHAKE_NONE		0x7f
+#define GSMI_LOG_ENTRY_TYPE_KERNEL	0xDEAD
+
+struct gsmi_set_eventlog_param {
+	u32 data_ptr;
+	u32 data_len;
+	u32 type;
+} __attribute__ ((packed));
+
+struct gsmi_set_eventlog_type1 {
+	u16 type;
+	u32 instance;
+} __attribute__ ((packed));
+
+struct gsmi_clear_eventlog_param {
+	u32 percentage;
+	u32 data_type;
+} __attribute__ ((packed));
+
+/* Param is usually EBX, ret in EAX */
+u32 gsmi_exec(u8 command, u32 *param)
+{
+	struct gsmi_set_eventlog_param *sel;
+	struct gsmi_set_eventlog_type1 *type1;
+	struct gsmi_clear_eventlog_param *cel;
+	u32 ret = GSMI_RET_UNSUPPORTED;
+
+	switch (command) {
+	case GSMI_CMD_HANDSHAKE_TYPE:
+		/* Used by kernel to verify basic SMI functionality */
+		printk(BIOS_DEBUG, "GSMI Handshake\n");
+		ret = GSMI_HANDSHAKE_NONE;
+		break;
+
+	case GSMI_CMD_SET_EVENT_LOG:
+		/* Look for a type1 event */
+		sel = (struct gsmi_set_eventlog_param *)(*param);
+		if (!sel)
+			break;
+
+		/* Make sure the input is usable */
+		if (sel->type != 1 && sel->data_ptr != 0 &&
+		    sel->data_len != sizeof(struct gsmi_set_eventlog_type1))
+			break;
+
+		/* Event structure within the data buffer */
+		type1 = (struct gsmi_set_eventlog_type1 *)(sel->data_ptr);
+		if (!type1)
+			break;
+
+		printk(BIOS_DEBUG, "GSMI Set Event Log "
+		       "(type=0x%x instance=0x%x)\n",
+		       type1->type, type1->instance);
+
+		if (type1->type == GSMI_LOG_ENTRY_TYPE_KERNEL) {
+			/* Special case for linux kernel shutdown reason */
+			elog_add_event_dword(ELOG_TYPE_OS_EVENT,
+					     type1->instance);
+		} else {
+			/* Add other events that may be used for testing */
+			elog_add_event_dword(type1->type, type1->instance);
+		}
+		ret = GSMI_RET_SUCCESS;
+		break;
+
+	case GSMI_CMD_CLEAR_EVENT_LOG:
+		/* Get paramter buffer even though we don't use it */
+		cel = (struct gsmi_clear_eventlog_param *)(*param);
+		if (!cel)
+			break;
+
+		printk(BIOS_DEBUG, "GSMI Clear Event Log (%u%% type=%u)\n",
+		       cel->percentage, cel->data_type);
+
+		if (elog_clear() == 0)
+			ret = GSMI_RET_SUCCESS;
+		break;
+
+	default:
+		printk(BIOS_DEBUG, "GSMI Unknown: 0x%02x\n", command);
+		break;
+	}
+
+	return ret;
+}
diff --git a/src/include/elog.h b/src/include/elog.h
index 0542f68..7d89f45 100644
--- a/src/include/elog.h
+++ b/src/include/elog.h
@@ -115,6 +115,10 @@ extern void elog_add_event_dword(u8 event_type, u32 data);
 extern void elog_add_event_wake(u8 source, u32 instance);
 extern int elog_smbios_write_type15(unsigned long *current, int handle);
 
+#if CONFIG_ELOG_GSMI
+extern u32 gsmi_exec(u8 command, u32 *param);
+#endif
+
 #if CONFIG_ELOG_BOOT_COUNT
 u32 boot_count_read(void);
 u32 boot_count_increment(void);




More information about the coreboot mailing list