]> Joshua Wise's Git repositories - netwatch.git/blame - gdb/stub.c
Fix smm_type detection to actually detect, and add a state_num_regs routine.
[netwatch.git] / gdb / stub.c
CommitLineData
4e3ef36b
JW
1/* stub.c
2 * GDB stub system manipultion code.
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 <stdint.h>
36#include <msr.h>
37#include <output.h>
38#include <state.h>
39#include <demap.h>
40#include <paging.h>
41#include <reg-x86.h>
42#include "proto.h"
43#include "stub.h"
44
45void send_stop_packet();
46
47uint16_t saved_db_entry;
48uint64_t saved_db_entry_location;
49enum operating_mode step_start_mode;
50uint64_t saved_cs_base;
51uint64_t saved_eflags;
52uint64_t saved_cs_limit;
53uint64_t saved_cs_attrib;
54uint64_t saved_ss_base;
55uint64_t saved_ss_limit;
56uint64_t saved_ss_attrib;
57
58#define P64(x) (uint32_t)((x)>>32), (uint32_t)(x)
59
60static const enum state_reg_t regs32 [] = {
61 STATE_REG_EAX, STATE_REG_ECX, STATE_REG_EDX, STATE_REG_EBX,
62 STATE_REG_ESP, STATE_REG_EBP, STATE_REG_ESI, STATE_REG_EDI,
63 STATE_REG_EIP, STATE_REG_EFLAGS, STATE_REG_CS, STATE_REG_SS,
64 STATE_REG_DS, STATE_REG_ES, STATE_REG_FS, STATE_REG_GS
65};
66
67static enum run_mode run_mode;
68
69void set_run_mode(enum run_mode mode) {
70 run_mode = mode;
71}
72
73int gdb_post_smi_hook() {
74 uint64_t r, entry;
75 uint32_t * ptr;
76 uint16_t * entry_v;
77 enum operating_mode m = get_operating_mode();
78
79
80 switch (run_mode) {
81 case RM_STOPPED:
82 /* Until we have a better way of handling this - spin in
83 * a loop. */
84 return 1;
85
86 case RM_STEPPING:
87 /* First, set RFLAGS.TF */
88 r = state_get_reg(STATE_REG_EFLAGS);
89 saved_eflags = r;
90 r |= EFLAGS_TF;
91 /* We also don't want to deal with interrupts. */
92 r &= ~EFLAGS_IF;
93 state_set_reg(STATE_REG_EFLAGS, r);
94
95 /* Track down the handler for a debug exception */
96 r = state_get_reg(STATE_REG_IDT_LIMIT);
97 r = state_get_reg(STATE_REG_IDT_BASE);
98 if (m == LONG_64BIT || m == LONG_COMPAT) {
99 /* 64-bit. Index up 16 bytes to get to the
100 * debug trap descriptor. */
101 ptr = demap(r + 16);
102 entry = (*ptr) & 0xFFFF;
103 ptr = demap(r + 20);
104 entry |= (*ptr) & 0xFFFF0000;
105 ptr = demap(r + 24);
106 entry |= (uint64_t)(*ptr) << 32;
107 } else {
108 /* Assume 32-bit for now. */
109 ptr = demap(r + 8);
110 entry = (*ptr) & 0xFFFF;
111 ptr = demap(r + 12);
112 entry |= (*ptr) & 0xFFFF0000;
113 }
114
115 outputf("entry is at %08x %08x", (uint32_t)(entry>>32), (uint32_t)entry);
116 /* MAGIC_BREAK */
117 saved_db_entry_location = demap_phys(entry);
118 entry_v = p2v(saved_db_entry_location);
119 outputf("entry_v mapped to %08x", entry_v);
120 if (!entry_v) {
121 run_mode = RM_UNENCUMBERED; break;
122 }
123 saved_db_entry = *entry_v;
124 *entry_v = 0xB2E6; /* "out %al, $0xb2" */
125
126 step_start_mode = m;
127
128 /* Turn off the safety */
129 WRMSR(0xc0010054, 0x8002);
130 outputf("Have fun!");
131
132 saved_cs_base = state_get_reg(STATE_REG_CS_BASE);
133 saved_cs_limit = state_get_reg(STATE_REG_CS_LIMIT);
134 saved_cs_attrib = state_get_reg(STATE_REG_CS_ATTRIB);
135 saved_ss_base = state_get_reg(STATE_REG_SS_BASE);
136 saved_ss_limit = state_get_reg(STATE_REG_SS_LIMIT);
137 saved_ss_attrib = state_get_reg(STATE_REG_SS_ATTRIB);
138
139 break;
140
141 case RM_CONTINUING:
142 /* There may be breakpoints. Fall through to
143 * "unencumbered" for now. */
144
145 case RM_UNENCUMBERED:
146 /* Nada. */
147 return 0;
148
149 default:
150 break;
151 }
152
153 return 0;
154}
155
156#define READ_QWORD(pa) ({ uint64_t * p = demap(pa); if (!p) goto fail; outputf("pq %08x %08x", (uint32_t)((*p)>>32), (uint32_t)(*p)); *p; })
157#define READ_WORD(pa) ({ uint16_t * p = demap(pa); if (!p) goto fail; outputf("p %04x", (*p)); *p; })
158
159static void gdb_unmangle_stepped_system() {
160 uint64_t r;
161 uint16_t * entry_v;
162
163 /* The unexpected breakpoint has caused an interrupt stack to be
164 * built, which we must get rid of. */
165
166 if (step_start_mode == LONG_64BIT) {
167 r = state_get_reg(STATE_REG_RSP);
168 state_set_reg(STATE_REG_RIP, READ_QWORD(r));
169 state_set_reg(STATE_REG_CS, READ_WORD(r+8));
170 state_set_reg(STATE_REG_RFLAGS, READ_QWORD(r+16));
171 state_set_reg(STATE_REG_RSP, READ_QWORD(r+24));
172 state_set_reg(STATE_REG_SS, READ_WORD(r+32));
173 } else if (step_start_mode == LONG_COMPAT) {
174 r = state_get_reg(STATE_REG_RSP);
175 state_set_reg(STATE_REG_RIP, READ_QWORD(r) & 0xFFFFFFFF);
176 state_set_reg(STATE_REG_CS, READ_WORD(r+8));
177 state_set_reg(STATE_REG_RFLAGS, READ_QWORD(r+16) & 0xFFFFFFFF);
178 state_set_reg(STATE_REG_RSP, READ_QWORD(r+24) & 0xFFFFFFFF);
179 state_set_reg(STATE_REG_SS, READ_WORD(r+32));
180 }
181 entry_v = p2v(saved_db_entry_location);
182 *entry_v = saved_db_entry;
183
184 state_set_reg(STATE_REG_CS_BASE, saved_cs_base);
185 state_set_reg(STATE_REG_CS_LIMIT, saved_cs_limit);
186 state_set_reg(STATE_REG_CS_ATTRIB, saved_cs_attrib);
187 state_set_reg(STATE_REG_SS_BASE, saved_ss_base);
188 state_set_reg(STATE_REG_SS_LIMIT, saved_ss_limit);
189 state_set_reg(STATE_REG_SS_ATTRIB, saved_ss_attrib);
190 state_set_reg(STATE_REG_EFLAGS, saved_eflags);
191
192 /* Put us back in "stopped" mode, until the GDB server gets around
193 * to handling the step.
194 */
195
196 reset_operating_mode_memo();
197 run_mode = RM_STOPPED;
198
199 send_stop_packet();
200 return;
201
202fail:
203 outputf("ERROR: Failed to restore state!");
204 while(1);
205}
206
207void gdb_pre_smi_hook() {
208 enum operating_mode m = get_operating_mode();
209 uint64_t ip, break_phys;
210
211 if (run_mode == RM_STEPPING) {
212 /* Oh hey, we are probably stopped on a breakpoint.
213 * Let's check. */
214 ip = state_get_reg(
215 (m == LONG_64BIT)
216 ? STATE_REG_RIP : STATE_REG_EIP
217 );
218 break_phys = demap_phys(ip);
219
220 if ((break_phys != saved_db_entry_location)
221 && (break_phys != saved_db_entry_location + 2)) {
222 /* Some other event caused us to enter SMM. We'll deal
223 * with the single step when we *actually* get to
224 * the breakpoint. */
225 return;
226 }
227
228 /* Great. Now we have caused a debug exception.
229 *
230 * "Your problems just got worse. Think: what have you done?"
231 *
232 * We don't want the running system to know that anything
233 * ever happened, so we manually unwind the stack and undo
234 * everything that happened.
235 */
236
237 gdb_unmangle_stepped_system();
238 }
239}
240
241
242void read_registers_32 (char * buf) {
243 int i, r = 0, offset = 0, size = 0;
244
245 /* Dump registers to buffer. */
246
247 for (i = 0; i < (sizeof(regs32) / sizeof(enum state_reg_t)); i++) {
248 enum state_reg_t reg = regs32[i];
249 r = state_get_reg(reg);
250 //size = state_reg_size(reg);
251 size = 4;
252 enhexificate(&r, buf + offset, size);
253 offset += (size * 2);
254 }
255
256 /* XXX: The rest of the buffer "should be" filled with floating point
257 stuff. We'll worry about that later. */
258}
259
260void write_registers_32 (char * buf) {
261 //int size = 0, i;
262
263
264 uint32_t *ubuf = (uint32_t *)buf;
265
266 state_set_reg(STATE_REG_EAX, ubuf[0]);
267 state_set_reg(STATE_REG_ECX, ubuf[1]);
268 state_set_reg(STATE_REG_EDX, ubuf[2]);
269 state_set_reg(STATE_REG_EBX, ubuf[3]);
270 state_set_reg(STATE_REG_ESP, ubuf[4]);
271 state_set_reg(STATE_REG_EBP, ubuf[5]);
272 state_set_reg(STATE_REG_ESI, ubuf[6]);
273 state_set_reg(STATE_REG_EDI, ubuf[7]);
274
275 state_set_reg(STATE_REG_EIP, ubuf[8]);
276 state_set_reg(STATE_REG_EFLAGS, ubuf[9]);
277 state_set_reg(STATE_REG_CS, ubuf[10]);
278 state_set_reg(STATE_REG_SS, ubuf[11]);
279 state_set_reg(STATE_REG_DS, ubuf[12]);
280 state_set_reg(STATE_REG_ES, ubuf[13]);
281 state_set_reg(STATE_REG_FS, ubuf[14]);
282 state_set_reg(STATE_REG_GS, ubuf[15]);
283
284 /* XXX: Again, need to deal with floating point. */
285}
This page took 0.049774 seconds and 4 git commands to generate.