]> Joshua Wise's Git repositories - netwatch.git/blob - gdb/stub.c
Fix smm_type detection to actually detect, and add a state_num_regs routine.
[netwatch.git] / gdb / stub.c
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
45 void send_stop_packet();
46
47 uint16_t saved_db_entry;
48 uint64_t saved_db_entry_location;
49 enum operating_mode step_start_mode;
50 uint64_t saved_cs_base;
51 uint64_t saved_eflags;
52 uint64_t saved_cs_limit;
53 uint64_t saved_cs_attrib;
54 uint64_t saved_ss_base;
55 uint64_t saved_ss_limit;
56 uint64_t saved_ss_attrib;
57
58 #define P64(x)  (uint32_t)((x)>>32), (uint32_t)(x)
59
60 static 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
67 static enum run_mode run_mode;
68
69 void set_run_mode(enum run_mode mode) {
70         run_mode = mode;
71 }
72
73 int 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
159 static 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
202 fail:
203         outputf("ERROR: Failed to restore state!");
204         while(1);
205 }
206
207 void 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
242 void 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
260 void 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.042839 seconds and 4 git commands to generate.