blob: f125d237fb25f71181e60d5e7ed1ccbda0d71066 [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.
Duncan Laurie79bbbd92012-06-23 16:48:38 -070014 */
15
16#include <arch/io.h>
17#include <console/console.h>
18#include <cpu/x86/smm.h>
19#include <elog.h>
20
21#define GSMI_RET_SUCCESS 0x00
22#define GSMI_RET_INVALID_PARAMETER 0x82
23#define GSMI_RET_UNSUPPORTED 0x83
24
25#define GSMI_CMD_SET_EVENT_LOG 0x08
26#define GSMI_CMD_CLEAR_EVENT_LOG 0x09
27#define GSMI_CMD_HANDSHAKE_TYPE 0xc1
28
29#define GSMI_HANDSHAKE_NONE 0x7f
30#define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD
31
32struct gsmi_set_eventlog_param {
33 u32 data_ptr;
34 u32 data_len;
35 u32 type;
36} __attribute__ ((packed));
37
38struct gsmi_set_eventlog_type1 {
39 u16 type;
40 u32 instance;
41} __attribute__ ((packed));
42
43struct gsmi_clear_eventlog_param {
44 u32 percentage;
45 u32 data_type;
46} __attribute__ ((packed));
47
48/* Param is usually EBX, ret in EAX */
49u32 gsmi_exec(u8 command, u32 *param)
50{
51 struct gsmi_set_eventlog_param *sel;
52 struct gsmi_set_eventlog_type1 *type1;
53 struct gsmi_clear_eventlog_param *cel;
54 u32 ret = GSMI_RET_UNSUPPORTED;
55
56 switch (command) {
57 case GSMI_CMD_HANDSHAKE_TYPE:
58 /* Used by kernel to verify basic SMI functionality */
59 printk(BIOS_DEBUG, "GSMI Handshake\n");
60 ret = GSMI_HANDSHAKE_NONE;
61 break;
62
63 case GSMI_CMD_SET_EVENT_LOG:
64 /* Look for a type1 event */
65 sel = (struct gsmi_set_eventlog_param *)(*param);
66 if (!sel)
67 break;
68
69 /* Make sure the input is usable */
70 if (sel->type != 1 && sel->data_ptr != 0 &&
71 sel->data_len != sizeof(struct gsmi_set_eventlog_type1))
72 break;
73
74 /* Event structure within the data buffer */
75 type1 = (struct gsmi_set_eventlog_type1 *)(sel->data_ptr);
76 if (!type1)
77 break;
78
79 printk(BIOS_DEBUG, "GSMI Set Event Log "
80 "(type=0x%x instance=0x%x)\n",
81 type1->type, type1->instance);
82
83 if (type1->type == GSMI_LOG_ENTRY_TYPE_KERNEL) {
84 /* Special case for linux kernel shutdown reason */
85 elog_add_event_dword(ELOG_TYPE_OS_EVENT,
86 type1->instance);
87 } else {
88 /* Add other events that may be used for testing */
89 elog_add_event_dword(type1->type, type1->instance);
90 }
91 ret = GSMI_RET_SUCCESS;
92 break;
93
94 case GSMI_CMD_CLEAR_EVENT_LOG:
Martin Roth56889792013-07-09 21:39:46 -060095 /* Get parameter buffer even though we don't use it */
Duncan Laurie79bbbd92012-06-23 16:48:38 -070096 cel = (struct gsmi_clear_eventlog_param *)(*param);
97 if (!cel)
98 break;
99
100 printk(BIOS_DEBUG, "GSMI Clear Event Log (%u%% type=%u)\n",
101 cel->percentage, cel->data_type);
102
103 if (elog_clear() == 0)
104 ret = GSMI_RET_SUCCESS;
105 break;
106
107 default:
108 printk(BIOS_DEBUG, "GSMI Unknown: 0x%02x\n", command);
109 break;
110 }
111
112 return ret;
113}