blob: b8bc253b590e249a349ca1d31fd9c74daa399038 [file] [log] [blame]
Duncan Laurie79bbbd92012-06-23 16:48:38 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
18 */
19
20#include <arch/io.h>
21#include <console/console.h>
22#include <cpu/x86/smm.h>
23#include <elog.h>
24
25#define GSMI_RET_SUCCESS 0x00
26#define GSMI_RET_INVALID_PARAMETER 0x82
27#define GSMI_RET_UNSUPPORTED 0x83
28
29#define GSMI_CMD_SET_EVENT_LOG 0x08
30#define GSMI_CMD_CLEAR_EVENT_LOG 0x09
31#define GSMI_CMD_HANDSHAKE_TYPE 0xc1
32
33#define GSMI_HANDSHAKE_NONE 0x7f
34#define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD
35
36struct gsmi_set_eventlog_param {
37 u32 data_ptr;
38 u32 data_len;
39 u32 type;
40} __attribute__ ((packed));
41
42struct gsmi_set_eventlog_type1 {
43 u16 type;
44 u32 instance;
45} __attribute__ ((packed));
46
47struct gsmi_clear_eventlog_param {
48 u32 percentage;
49 u32 data_type;
50} __attribute__ ((packed));
51
52/* Param is usually EBX, ret in EAX */
53u32 gsmi_exec(u8 command, u32 *param)
54{
55 struct gsmi_set_eventlog_param *sel;
56 struct gsmi_set_eventlog_type1 *type1;
57 struct gsmi_clear_eventlog_param *cel;
58 u32 ret = GSMI_RET_UNSUPPORTED;
59
60 switch (command) {
61 case GSMI_CMD_HANDSHAKE_TYPE:
62 /* Used by kernel to verify basic SMI functionality */
63 printk(BIOS_DEBUG, "GSMI Handshake\n");
64 ret = GSMI_HANDSHAKE_NONE;
65 break;
66
67 case GSMI_CMD_SET_EVENT_LOG:
68 /* Look for a type1 event */
69 sel = (struct gsmi_set_eventlog_param *)(*param);
70 if (!sel)
71 break;
72
73 /* Make sure the input is usable */
74 if (sel->type != 1 && sel->data_ptr != 0 &&
75 sel->data_len != sizeof(struct gsmi_set_eventlog_type1))
76 break;
77
78 /* Event structure within the data buffer */
79 type1 = (struct gsmi_set_eventlog_type1 *)(sel->data_ptr);
80 if (!type1)
81 break;
82
83 printk(BIOS_DEBUG, "GSMI Set Event Log "
84 "(type=0x%x instance=0x%x)\n",
85 type1->type, type1->instance);
86
87 if (type1->type == GSMI_LOG_ENTRY_TYPE_KERNEL) {
88 /* Special case for linux kernel shutdown reason */
89 elog_add_event_dword(ELOG_TYPE_OS_EVENT,
90 type1->instance);
91 } else {
92 /* Add other events that may be used for testing */
93 elog_add_event_dword(type1->type, type1->instance);
94 }
95 ret = GSMI_RET_SUCCESS;
96 break;
97
98 case GSMI_CMD_CLEAR_EVENT_LOG:
Martin Roth56889792013-07-09 21:39:46 -060099 /* Get parameter buffer even though we don't use it */
Duncan Laurie79bbbd92012-06-23 16:48:38 -0700100 cel = (struct gsmi_clear_eventlog_param *)(*param);
101 if (!cel)
102 break;
103
104 printk(BIOS_DEBUG, "GSMI Clear Event Log (%u%% type=%u)\n",
105 cel->percentage, cel->data_type);
106
107 if (elog_clear() == 0)
108 ret = GSMI_RET_SUCCESS;
109 break;
110
111 default:
112 printk(BIOS_DEBUG, "GSMI Unknown: 0x%02x\n", command);
113 break;
114 }
115
116 return ret;
117}