]> Joshua Wise's Git repositories - netwatch.git/blame - lib/state.c
Apply patches from jdpotter@google.com, as submitted to NetWatch Maintainer Team...
[netwatch.git] / lib / state.c
CommitLineData
db9fad13
JAW
1/* state.c
2 * SMM saved state manipulation functions.
3 * NetWatch system management mode administration console
4 *
5 * Copyright 2009, Google Inc.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 * * Neither the name of Google Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "state.h"
36#include <cpuid.h>
37
38/* Size flags. */
39#define SZ_BYTE 0x10000000
40#define SZ_WORD 0x20000000
41#define SZ_DWORD 0x40000000
42#define SZ_QWORD 0x80000000
43#define OFFSET_MASK 0x0FFFFFFF
44
45static const uint32_t offset_table_legacy[] = {
46 [STATE_REV] = 0xfefc | SZ_DWORD,
47 [STATE_REG_SMBASE] = 0xfef8 | SZ_DWORD,
48 [STATE_REG_IORESTART] = 0xff00 | SZ_WORD,
49 [STATE_REG_HALTRESTART] = 0xff02 | SZ_WORD,
50
51 [STATE_REG_EAX] = 0xffd0 | SZ_DWORD,
52 [STATE_REG_EBX] = 0xffdc | SZ_DWORD,
53 [STATE_REG_ECX] = 0xffd4 | SZ_DWORD,
54 [STATE_REG_EDX] = 0xffd8 | SZ_DWORD,
55 [STATE_REG_ESI] = 0xffe8 | SZ_DWORD,
56 [STATE_REG_EDI] = 0xffec | SZ_DWORD,
57 [STATE_REG_ESP] = 0xffe0 | SZ_DWORD,
58 [STATE_REG_EBP] = 0xffe4 | SZ_DWORD,
59 [STATE_REG_EIP] = 0xfff0 | SZ_DWORD,
60 [STATE_REG_EFLAGS] = 0xfff4 | SZ_DWORD,
61 [STATE_REG_CR0] = 0xfffc | SZ_DWORD,
62 [STATE_REG_CR3] = 0xfff8 | SZ_DWORD,
63
64 [STATE_REG_CS] = 0xffac | SZ_DWORD,
65 [STATE_REG_SS] = 0xffb0 | SZ_DWORD,
66 [STATE_REG_DS] = 0xffb4 | SZ_DWORD,
67 [STATE_REG_ES] = 0xffa8 | SZ_DWORD,
68 [STATE_REG_FS] = 0xffb8 | SZ_DWORD,
69 [STATE_REG_GS] = 0xffbc | SZ_DWORD
70};
71
72#define MAX_REG_LEGACY (sizeof(offset_table_legacy)/sizeof(uint32_t))
73
74static const uint32_t offset_table_amd64[] = {
75 [STATE_REV] = 0xfefc | SZ_DWORD,
76 [STATE_REG_SMBASE] = 0xff00 | SZ_DWORD,
77 [STATE_REG_IORESTART] = 0xfec8 | SZ_BYTE,
78 [STATE_REG_HALTRESTART] = 0xfec9 | SZ_BYTE,
79
80 [STATE_REG_EAX] = 0xfff8 | SZ_DWORD,
81 [STATE_REG_EBX] = 0xffe0 | SZ_DWORD,
82 [STATE_REG_ECX] = 0xfff0 | SZ_DWORD,
83 [STATE_REG_EDX] = 0xffe8 | SZ_DWORD,
84 [STATE_REG_ESI] = 0xffc8 | SZ_DWORD,
85 [STATE_REG_EDI] = 0xffc0 | SZ_DWORD,
86 [STATE_REG_ESP] = 0xffd8 | SZ_DWORD,
87 [STATE_REG_EBP] = 0xffd0 | SZ_DWORD,
88 [STATE_REG_EIP] = 0xff78 | SZ_DWORD,
89 [STATE_REG_EFLAGS] = 0xff70 | SZ_DWORD,
90 [STATE_REG_CR0] = 0xff58 | SZ_DWORD,
91 [STATE_REG_CR3] = 0xff50 | SZ_DWORD,
92
93 [STATE_REG_CS] = 0xfe10 | SZ_DWORD,
94 [STATE_REG_SS] = 0xfe20 | SZ_DWORD,
95 [STATE_REG_DS] = 0xfe30 | SZ_DWORD,
96 [STATE_REG_ES] = 0xfe00 | SZ_DWORD,
97 [STATE_REG_FS] = 0xfe40 | SZ_DWORD,
98 [STATE_REG_GS] = 0xfe50 | SZ_DWORD,
99
100 [STATE_REG_RAX] = 0xfff8 | SZ_QWORD,
101 [STATE_REG_RBX] = 0xffe0 | SZ_QWORD,
102 [STATE_REG_RCX] = 0xfff0 | SZ_QWORD,
103 [STATE_REG_RDX] = 0xffe8 | SZ_QWORD,
104 [STATE_REG_RSI] = 0xffc8 | SZ_QWORD,
105 [STATE_REG_RDI] = 0xffc0 | SZ_QWORD,
106 [STATE_REG_RSP] = 0xffd8 | SZ_QWORD,
107 [STATE_REG_RBP] = 0xffd0 | SZ_QWORD,
108 [STATE_REG_R8] = 0xffb8 | SZ_QWORD,
109 [STATE_REG_R9] = 0xffb0 | SZ_QWORD,
110 [STATE_REG_R10] = 0xffa8 | SZ_QWORD,
111 [STATE_REG_R11] = 0xffa0 | SZ_QWORD,
112 [STATE_REG_R12] = 0xff98 | SZ_QWORD,
113 [STATE_REG_R13] = 0xff90 | SZ_QWORD,
114 [STATE_REG_R14] = 0xff88 | SZ_QWORD,
115 [STATE_REG_R15] = 0xff80 | SZ_QWORD,
116 [STATE_REG_RIP] = 0xff78 | SZ_QWORD
117};
118
119#define MAX_REG_AMD64 (sizeof(offset_table_amd64)/sizeof(uint32_t))
120
121static enum smm_type smm_type = SMM_TYPE_64;
122
123/* Probe CPUID to figure out what kind of processor this actually is.
124 * We memoize this in 'smm_type', so cpuid only needs to happen once.
125 */
126
127static void check_smm_type (void) {
128
129 struct cpuid_result r;
130
131 if (smm_type != SMM_TYPE_UNKNOWN)
132 return;
133
134 cpuid(0x80000000, &r);
135
136 if (r.eax < 0x80000001) {
137 smm_type = SMM_TYPE_32;
138 return;
139 }
140
141 cpuid(0x80000001, &r);
142
143 if (r.edx & 0x20000000) {
144 smm_type = SMM_TYPE_64;
145 } else {
146 smm_type = SMM_TYPE_32;
147 }
148}
149
150/* Get the offset of a register, by looking up in the appropriate table.
151 */
152
153static unsigned long get_offset(enum state_reg_t reg) {
154
155 check_smm_type();
156
157 if (smm_type == SMM_TYPE_32 && reg < MAX_REG_LEGACY)
158 return offset_table_legacy[reg];
159 else if (smm_type == SMM_TYPE_64 && reg < MAX_REG_AMD64)
160 return offset_table_amd64[reg];
161 else
162 return 0;
163}
164
165/* Which variety of processor are we running on?
166 */
167
168enum smm_type state_get_type (void) {
169 check_smm_type();
170 return smm_type;
171}
172
173/* Get a register.
174 *
175 * We assume that Aseg is always direct-mapped at 0xA0000. This may
176 * not be the case in the future, with multiple cores, but it is a
177 * safe assumption now.
178 */
179
180uint64_t state_get_reg (enum state_reg_t reg) {
181 unsigned long offset = get_offset(reg);
182 void * addr;
183 uint64_t value;
184
185 if (!offset)
186 return 0;
187
188 addr = (void *)((offset & OFFSET_MASK) + 0xA0000);
189
190 if (offset & SZ_BYTE)
191 value = *(uint8_t *)addr;
192 else if (offset & SZ_WORD)
193 value = *(uint16_t *)addr;
194 else if (offset & SZ_DWORD)
195 value = *(uint32_t *)addr;
196 else
197 value = *(uint64_t *)addr;
198
199 return value;
200}
201
202/* Get the size of a register, extracted from the saved state offset table.
203 */
204
205int state_reg_size (enum state_reg_t reg) {
206 unsigned long offset = get_offset(reg);
207
208 if (offset & SZ_BYTE) return 1;
209 else if (offset & SZ_WORD) return 2;
210 else if (offset & SZ_DWORD) return 4;
211 else if (offset & SZ_QWORD) return 8;
212 else return 0;
213}
214
215/* Modify a saved register.
216 *
217 * The same caveat about aseg's location applies here as well.
218 */
219
220int state_set_reg (enum state_reg_t reg, uint64_t value) {
221 unsigned long offset = get_offset(reg);
222 void * addr;
223
224 if (!offset)
225 return -1;
226
227 addr = (void *)((offset & OFFSET_MASK) + 0xA0000);
228
229 if (offset & SZ_BYTE)
230 *(uint8_t *)addr = (uint8_t) value;
231 else if (offset & SZ_WORD)
232 *(uint16_t *)addr = (uint16_t) value;
233 else if (offset & SZ_DWORD)
234 *(uint32_t *)addr = (uint32_t) value;
235 else
236 *(uint64_t *)addr = value;
237
238 return 0;
239}
This page took 0.041893 seconds and 4 git commands to generate.