1 /*
2 * Copyright (C) 2009, Mukesh Rathor, Oracle Corp. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public
14 * License along with this program; If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 /* This is the main module to interface with xen. This module exports APIs that
18 * allow for creating any remote debugger plugin. The APIs are:
19 *
20 * xg_init() : initialize
21 * xg_attach(): attach to the given guest, preparing it for debug
22 * xg_detach_deinit(): exit debugging
23 *
24 * xg_step() : single step the the given vcpu
25 * xg_resume_n_wait(): resume the target guest and wait for any debug event
26 * xg_regs_read(): read context of given vcpu
27 * xg_regs_write(): write context of given vcpu
28 * xg_read_mem(): read memory of guest at given VA
29 * xg_write_mem(): write memory of guest at given VA
30 *
31 * XGERR(): generic print error utility
32 * XGTRC(): generic trace utility
33 */
34
35 #include <sys/types.h>
36 #include <stdio.h>
37 #include <stddef.h>
38 #include <stdarg.h>
39 #include <stdint.h>
40 #include <unistd.h>
41 #include <sys/ioctl.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <sys/mman.h>
45 #include <string.h>
46 #include <time.h>
47 #include <assert.h>
48
49 #include "xg_public.h"
50 #include <xen/version.h>
51 #include <xen/domctl.h>
52 #include <xen/sys/privcmd.h>
53 #include <xen/foreign/x86_32.h>
54 #include <xen/foreign/x86_64.h>
55
56 #define XGMIN(x,y) (((x)<(y))?(x):(y))
57
58 #define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
59
60
61 /*
62 * Contexts returned by xen: (gdbsx : dom 0 : hypervisor)
63 *
64 * 32 : 32 : 32 => 64bit context never returned. can't run 64bit guests
65 * 32 : 32 : 64 => 32bit ctxt for 32bit PV guest. 64bit ctxt for 64 PV guests.
66 * HVM always 64bit ctxt.
67 * 32 : 64 : 64 => N/A
68 * 64 : 64 : 64 => Same as 32:32:64 (CONFIG_COMPAT is almost always defined)
69 * 64 : 64 : 64 => !CONFIG_COMPAT : not supported.
70 */
71 typedef union vcpu_guest_context_any {
72 vcpu_guest_context_x86_64_t ctxt64;
73 vcpu_guest_context_x86_32_t ctxt32;
74 vcpu_guest_context_t ctxt;
75 } vcpu_guest_context_any_t;
76
77
78 int xgtrc_on = 0;
79 struct xen_domctl domctl; /* just use a global domctl */
80
81 static int _hvm_guest; /* hvm guest? 32bit HVMs have 64bit context */
82 static domid_t _dom_id; /* guest domid */
83 static int _max_vcpu_id; /* thus max_vcpu_id+1 VCPUs */
84 static int _dom0_fd; /* fd of /dev/privcmd */
85 static int _32bit_hyp; /* hyp is 32bit */
86
87
88 /* print trace info with function name pre-pended */
89 void
xgtrc(const char * fn,const char * fmt,...)90 xgtrc(const char *fn, const char *fmt, ...)
91 {
92 char buf[2048];
93 va_list args;
94
95 fprintf(stderr, "%s:", fn);
96 va_start(args, fmt);
97 (void)vsnprintf(buf, sizeof(buf), fmt, args);
98 va_end(args);
99 fprintf(stderr, "%s", buf);
100 fflush (stderr);
101 }
102
103 /* print error msg with function name pre-pended */
104 void
xgprt(const char * fn,const char * fmt,...)105 xgprt(const char *fn, const char *fmt, ...)
106 {
107 char buf[2048];
108 va_list args;
109
110 fprintf(stderr, "ERROR:%s:", fn);
111 va_start(args, fmt);
112 (void)vsnprintf(buf, sizeof(buf), fmt, args);
113 va_end(args);
114 fprintf (stderr, "%s", buf);
115 fflush (stderr);
116 }
117
118
119 /*
120 * Returns: 0 success
121 * -1 failure, errno set.
122 */
123 int
xg_init()124 xg_init()
125 {
126 int flags, saved_errno;
127
128 XGTRC("E\n");
129 if ((_dom0_fd=open("/dev/xen/privcmd", O_RDWR)) == -1) {
130 if ((_dom0_fd=open("/proc/xen/privcmd", O_RDWR)) == -1) {
131 perror("Failed to open /dev/xen/privcmd or /proc/xen/privcmd\n");
132 return -1;
133 }
134 }
135 /* Although we return the file handle as the 'xc handle' the API
136 * does not specify / guarentee that this integer is in fact
137 * a file handle. Thus we must take responsiblity to ensure
138 * it doesn't propagate (ie leak) outside the process (copied comment)*/
139 if ( (flags=fcntl(_dom0_fd, F_GETFD)) < 0 ) {
140 perror("Could not get file handle flags (F_GETFD)");
141 goto error;
142 }
143 flags |= FD_CLOEXEC;
144 if (fcntl(_dom0_fd, F_SETFD, flags) < 0) {
145 perror("Could not set file handle flags");
146 goto error;
147 }
148
149 XGTRC("X:fd:%d\n", _dom0_fd);
150 return _dom0_fd;
151
152 error:
153 XGTRC("X:Error: errno:%d\n", errno);
154 saved_errno = errno;
155 close(_dom0_fd);
156 errno = saved_errno;
157 return -1;
158 }
159
160
161 /*
162 * Precondition: domctl global struct must be filled
163 * Returns : 0 Success, failure otherwise with errno set
164 */
165 static int
_domctl_hcall(uint32_t cmd,void * domctlarg,int sz)166 _domctl_hcall(uint32_t cmd, /* which domctl hypercall */
167 void *domctlarg, /* arg/buf to domctl to pin in mem */
168 int sz) /* size of *domctlarg */
169 {
170 privcmd_hypercall_t hypercall;
171 int rc;
172
173 if (domctlarg && sz && mlock(domctlarg, sz)) {
174 XGERR("Unable to pin domctl arg. p:%p sz:%d errno:%d\n",
175 domctlarg, sz, errno);
176 return 1;
177 }
178 domctl.cmd = cmd;
179 hypercall.op = __HYPERVISOR_domctl;
180 hypercall.arg[0] = (unsigned long)&domctl;
181
182 rc = ioctl(_dom0_fd, IOCTL_PRIVCMD_HYPERCALL, &hypercall);
183 if (domctlarg && sz)
184 munlock(domctlarg, sz);
185 return rc;
186 }
187
188 /*
189 * Make sure we are running on hyp enabled for gdbsx. Also, note whether
190 * its 32bit. Fail if user typed 64bit for guest in case of 32bit hyp.
191 *
192 * RETURNS: 0 : everything OK.
193 */
194 static int
_check_hyp(int guest_bitness)195 _check_hyp(int guest_bitness)
196 {
197 xen_capabilities_info_t xen_caps = "";
198 privcmd_hypercall_t hypercall;
199 int rc;
200
201 /*
202 * Try to unpause an invalid vcpu. If hypervisor supports gdbsx then
203 * this should fail with an error other than ENOSYS.
204 */
205 domctl.u.gdbsx_pauseunp_vcpu.vcpu = ~0u;
206 (void)_domctl_hcall(XEN_DOMCTL_gdbsx_unpausevcpu, NULL, 0);
207 if (errno == ENOSYS) {
208 XGERR("Hyp is NOT enabled for gdbsx\n");
209 return -1;
210 }
211
212 if (mlock(&xen_caps, sizeof(xen_caps))) {
213 XGERR("Unable to pin xen_caps in memory. errno:%d\n", errno);
214 return -1;
215 }
216 memset(&xen_caps, 0, sizeof(xen_caps));
217
218 hypercall.op = __HYPERVISOR_xen_version;
219 hypercall.arg[0] = (unsigned long)XENVER_capabilities;
220 hypercall.arg[1] = (unsigned long)&xen_caps;
221
222 rc = ioctl(_dom0_fd, IOCTL_PRIVCMD_HYPERCALL, &hypercall);
223 munlock(&xen_caps, sizeof(xen_caps));
224 XGTRC("XENCAPS:%s\n", xen_caps);
225
226 if (rc != 0) {
227 XGERR("Failed xen_version hcall. errno:%d\n", errno);
228 return -1;
229 }
230
231 _32bit_hyp = (strstr(xen_caps, "x86_64") == NULL);
232 if (_32bit_hyp && guest_bitness !=32) {
233 XGERR("32bit hyp can only run 32bit guests\n");
234 return -1;
235 }
236 return 0;
237 }
238
239 /* check if domain is alive and well
240 * returns : 0 if domain is not alive and well
241 */
242 static int
_domain_ok(struct xen_domctl_getdomaininfo * domp)243 _domain_ok(struct xen_domctl_getdomaininfo *domp)
244 {
245 int rc = 0;
246 if (domp->flags & XEN_DOMINF_dying)
247 XGERR("Invalid domain (state dying)...\n");
248 else
249 rc = 1;
250 return rc;
251 }
252
253 /* Returns: 0 : success */
254 static int
_unpause_domain(void)255 _unpause_domain(void)
256 {
257 memset(&domctl.u, 0, sizeof(domctl.u));
258 if (_domctl_hcall(XEN_DOMCTL_unpausedomain, NULL, 0)) {
259 XGERR("Unable to unpause domain:%d errno:%d\n", _dom_id, errno);
260 return -1;
261 }
262 return 0;
263 }
264
265 /*
266 * Attach to the given domid for debugging.
267 * Returns: max vcpu id : Success
268 * -1 : Failure
269 */
270 int
xg_attach(int domid,int guest_bitness)271 xg_attach(int domid, int guest_bitness)
272 {
273 XGTRC("E:domid:%d\n", domid);
274
275 _dom_id = domctl.domain = domid;
276 domctl.interface_version = XEN_DOMCTL_INTERFACE_VERSION;
277
278 if (mlock(&domctl, sizeof(domctl))) {
279 XGERR("Unable to pin domctl in memory. errno:%d\n", errno);
280 return -1;
281 }
282 if (_check_hyp(guest_bitness))
283 return -1;
284
285 if (_domctl_hcall(XEN_DOMCTL_pausedomain, NULL, 0)) {
286 XGERR("Unable to pause domain:%d\n", _dom_id);
287 return -1;
288 }
289
290 memset(&domctl.u, 0, sizeof(domctl.u));
291 domctl.u.setdebugging.enable = 1;
292 if (_domctl_hcall(XEN_DOMCTL_setdebugging, NULL, 0)) {
293 XGERR("Unable to set domain to debug mode: errno:%d\n", errno);
294 _unpause_domain();
295 return -1;
296 }
297
298 memset(&domctl.u, 0, sizeof(domctl.u));
299 if (_domctl_hcall(XEN_DOMCTL_getdomaininfo, NULL, 0)) {
300 XGERR("Unable to get domain info: domid:%d errno:%d\n",
301 domid, errno);
302 _unpause_domain();
303 return -1;
304 }
305 if (!_domain_ok(&domctl.u.getdomaininfo)) {
306 _unpause_domain();
307 return -1;
308 }
309
310 _max_vcpu_id = domctl.u.getdomaininfo.max_vcpu_id;
311 _hvm_guest = (domctl.u.getdomaininfo.flags & XEN_DOMINF_hvm_guest);
312 return _max_vcpu_id;
313 }
314
315
316 /* Returns: 1 : domain is paused. 0 otherwise */
317 static int
_domain_is_paused(void)318 _domain_is_paused(void)
319 {
320 memset(&domctl.u, 0, sizeof(domctl.u));
321 if (_domctl_hcall(XEN_DOMCTL_getdomaininfo, NULL, 0)) {
322 XGERR("ERROR: Unable to get domain paused info:%d\n", _dom_id);
323 return 0;
324 }
325 return (domctl.u.getdomaininfo.flags & XEN_DOMINF_paused);
326 }
327
328 /* Detach from guest for debugger exit */
329 void
xg_detach_deinit(void)330 xg_detach_deinit(void)
331 {
332 memset(&domctl.u, 0, sizeof(domctl.u));
333 domctl.u.setdebugging.enable = 0;
334 if (_domctl_hcall(XEN_DOMCTL_setdebugging, NULL, 0)) {
335 XGERR("Unable to reset domain debug mode: errno:%d\n", errno);
336 }
337 if (_domain_is_paused())
338 _unpause_domain();
339
340 close(_dom0_fd);
341 }
342
343 /*
344 * Returns : 0 success.
345 * 1 error, with errno set (hopefully :))
346 */
347 static int
_wait_domain_pause(void)348 _wait_domain_pause(void)
349 {
350 int dom_paused;
351 struct timespec ts={0, 10*1000*1000};
352
353 XGTRC("E:\n");
354 do {
355 dom_paused = _domain_is_paused();
356 nanosleep(&ts, NULL);
357 } while(!dom_paused);
358 return 0;
359 }
360
361 /*
362 * Change the TF flag for single step. TF = (setit ? 1 : 0);
363 * Returns: 0 Success
364 */
365 static int
_change_TF(vcpuid_t which_vcpu,int guest_bitness,int setit)366 _change_TF(vcpuid_t which_vcpu, int guest_bitness, int setit)
367 {
368 union vcpu_guest_context_any anyc;
369 int sz = sizeof(anyc);
370
371 /* first try the MTF for hvm guest. otherwise do manually */
372 if (_hvm_guest) {
373 domctl.u.debug_op.vcpu = which_vcpu;
374 domctl.u.debug_op.op = setit ? XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON :
375 XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF;
376
377 if (_domctl_hcall(XEN_DOMCTL_debug_op, NULL, 0) == 0) {
378 XGTRC("vcpu:%d:MTF success setit:%d\n", which_vcpu, setit);
379 return 0;
380 }
381 XGTRC("vcpu:%d:MTF failed. setit:%d\n", which_vcpu, setit);
382 }
383
384 memset(&anyc, 0, sz);
385 domctl.u.vcpucontext.vcpu = (uint16_t)which_vcpu;
386 set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &anyc.ctxt);
387
388 if (_domctl_hcall(XEN_DOMCTL_getvcpucontext, &anyc, sz)) {
389 XGERR("Failed hcall to get vcpu ctxt for TF. errno:%d\n",errno);
390 return 1;
391 }
392 if (_32bit_hyp || (guest_bitness == 32 && !_hvm_guest)) {
393 if (setit)
394 anyc.ctxt32.user_regs.eflags |= X86_EFLAGS_TF;
395 else
396 anyc.ctxt32.user_regs.eflags &= ~X86_EFLAGS_TF;
397 } else {
398 if (setit)
399 anyc.ctxt64.user_regs.rflags |= X86_EFLAGS_TF;
400 else
401 anyc.ctxt64.user_regs.rflags &= ~X86_EFLAGS_TF;
402 }
403
404 if (_domctl_hcall(XEN_DOMCTL_setvcpucontext, &anyc, sz)) {
405 XGERR("Failed hcall to set vcpu ctxt for TF. errno:%d\n",errno);
406 return 1;
407 }
408 return 0;
409 }
410
411 /* Do the given DOMCTL hcall action(pause or unpause) on all but the given vcpu
412 * Returns: 0 success */
413 static int
_allbutone_vcpu(uint32_t hcall,vcpuid_t which_vcpu)414 _allbutone_vcpu(uint32_t hcall, vcpuid_t which_vcpu)
415 {
416 int i;
417 for (i=0; i <= _max_vcpu_id; i++) {
418 if (i == which_vcpu)
419 continue;
420
421 memset(&domctl.u, 0, sizeof(domctl.u));
422 domctl.u.gdbsx_pauseunp_vcpu.vcpu = i;
423 if (_domctl_hcall(hcall, NULL, 0)) {
424 XGERR("Unable to do:%d vcpu:%d errno:%d\n",
425 hcall, i, errno);
426 return 1;
427 }
428 }
429 return 0;
430 }
431
432 /*
433 * Single step the given vcpu. This is achieved by pausing all but given vcpus,
434 * setting the TF flag, let the domain run and pause, unpause all vcpus, and
435 * clear TF flag on given vcpu.
436 * Returns: 0 success
437 */
438 int
xg_step(vcpuid_t which_vcpu,int guest_bitness)439 xg_step(vcpuid_t which_vcpu, int guest_bitness)
440 {
441 int rc;
442
443 XGTRC("E:vcpu:%d\n", (int)which_vcpu);
444
445 if (_allbutone_vcpu(XEN_DOMCTL_gdbsx_pausevcpu, which_vcpu))
446 return 1;
447
448 if ((rc=_change_TF(which_vcpu, guest_bitness, 1)))
449 return rc;
450
451 XGTRC("unpausing domain\n");
452
453 /* now unpause the domain so our vcpu can execute */
454 if (_unpause_domain())
455 return 1;
456
457 /* wait for our vcpu to finish step */
458 _wait_domain_pause();
459
460 _allbutone_vcpu(XEN_DOMCTL_gdbsx_unpausevcpu, which_vcpu);
461 rc = _change_TF(which_vcpu, guest_bitness, 0);
462
463 return rc;
464 }
465
466 /*
467 * check if any one of the vcpus is in a breakpoint
468 * Returns: vcpuid : if a vcpu found in a bp
469 * -1 : otherwise
470 */
471 static vcpuid_t
_vcpu_in_bp(void)472 _vcpu_in_bp(void)
473 {
474 memset(&domctl.u, 0, sizeof(domctl.u));
475 if (_domctl_hcall(XEN_DOMCTL_gdbsx_domstatus, NULL, 0)) {
476 XGERR("ERROR: Unable to check vcpu bp status:%d errno:%d\n",
477 _dom_id, errno);
478 return -1;
479 }
480 return domctl.u.gdbsx_domstatus.vcpu_id;
481 }
482
483 /*
484 * Resume the domain if no pending events. If there are pending events, like
485 * another vcpu in a BP, report it. Otherwise, continue, and wait till an
486 * event, like bp or user doing xm pause, occurs.
487 *
488 * Returns: vcpuid : if a vcpu hits a breakpoint or end of step
489 * -1 : either an error (msg printed on terminal), or non-bp
490 * event, like "xm pause domid", to enter debugger
491 */
492 vcpuid_t
xg_resume_n_wait(int guest_bitness)493 xg_resume_n_wait(int guest_bitness)
494 {
495 vcpuid_t vcpu;
496
497 XGTRC("E:\n");
498 assert(_domain_is_paused());
499
500 if ((vcpu=_vcpu_in_bp()) != -1) {
501 /* another vcpu in breakpoint. return it's id */
502 return vcpu;
503 }
504 XGTRC("unpausing domain\n");
505 if (_unpause_domain())
506 return -1;
507
508 /* now wait for domain to pause */
509 _wait_domain_pause();
510
511 /* check again if any vcpu in BP, or user thru "xm pause" */
512 vcpu = _vcpu_in_bp();
513
514 XGTRC("X:vcpu:%d\n", vcpu);
515 return vcpu;
516 }
517
518 static void
_cp_32ctxt_to_32gdb(struct cpu_user_regs_x86_32 * cp,struct xg_gdb_regs32 * rp)519 _cp_32ctxt_to_32gdb(struct cpu_user_regs_x86_32 *cp, struct xg_gdb_regs32 *rp)
520 {
521 memset(rp, 0, sizeof(struct xg_gdb_regs32));
522 rp->ebx = cp->ebx;
523 rp->ecx = cp->ecx;
524 rp->edx = cp->edx;
525 rp->esi = cp->esi;
526 rp->edi = cp->edi;
527 rp->ebp = cp->ebp;
528 rp->eax = cp->eax;
529 rp->eip = cp->eip;
530 rp->cs = cp->cs;
531 rp->eflags = cp->eflags;
532 rp->esp = cp->esp;
533 rp->ss = cp->ss;
534 rp->es = cp->es;
535 rp->ds = cp->ds;
536 rp->fs = cp->fs;
537 rp->gs = cp->gs;
538 }
539
540 static void
_cp_64ctxt_to_32gdb(struct cpu_user_regs_x86_64 * cp,struct xg_gdb_regs32 * rp)541 _cp_64ctxt_to_32gdb(struct cpu_user_regs_x86_64 *cp, struct xg_gdb_regs32 *rp)
542 {
543 memset(rp, 0, sizeof(struct xg_gdb_regs32));
544 rp->ebx = cp->rbx;
545 rp->ecx = cp->rcx;
546 rp->edx = cp->rdx;
547 rp->esi = cp->rsi;
548 rp->edi = cp->rdi;
549 rp->ebp = cp->rbp;
550 rp->eax = cp->rax;
551 rp->eip = cp->rip;
552 rp->cs = cp->cs;
553 rp->eflags = cp->rflags;
554 rp->esp = cp->rsp;
555 rp->ss = cp->ss;
556 rp->es = cp->es;
557 rp->ds = cp->ds;
558 rp->fs = cp->fs;
559 rp->gs = cp->gs;
560 }
561
562 static void
_cp_64ctxt_to_64gdb(struct cpu_user_regs_x86_64 * cp,struct xg_gdb_regs64 * rp)563 _cp_64ctxt_to_64gdb(struct cpu_user_regs_x86_64 *cp, struct xg_gdb_regs64 *rp)
564 {
565 memset(rp, 0, sizeof(struct xg_gdb_regs64));
566 rp->r8 = cp->r8;
567 rp->r9 = cp->r9;
568 rp->r10 = cp->r10;
569 rp->r11 = cp->r11;
570 rp->r12 = cp->r12;
571 rp->r13 = cp->r13;
572 rp->r14 = cp->r14;
573 rp->r15 = cp->r15;
574 rp->rbx = cp->rbx;
575 rp->rcx = cp->rcx;
576 rp->rdx = cp->rdx;
577 rp->rsi = cp->rsi;
578 rp->rdi = cp->rdi;
579 rp->rbp = cp->rbp;
580 rp->rax = cp->rax;
581 rp->rip = cp->rip;
582 rp->rsp = cp->rsp;
583 rp->rflags = cp->rflags;
584
585 rp->cs = (uint64_t)cp->cs;
586 rp->ss = (uint64_t)cp->ss;
587 rp->es = (uint64_t)cp->es;
588 rp->ds = (uint64_t)cp->ds;
589 rp->fs = (uint64_t)cp->fs;
590 rp->gs = (uint64_t)cp->gs;
591 #if 0
592 printf("cp:%llx bp:%llx rip:%llx\n", rp->rsp, rp->rbp, rp->rip);
593 printf("rax:%llx rbx:%llx\n", rp->rax, rp->rbx);
594 printf("cs:%04x ss:%04x ds:%04x\n", (int)rp->cs, (int)rp->ss,
595 (int)rp->ds);
596 #endif
597 }
598
599 static void
_cp_32gdb_to_32ctxt(struct xg_gdb_regs32 * rp,struct cpu_user_regs_x86_32 * cp)600 _cp_32gdb_to_32ctxt(struct xg_gdb_regs32 *rp, struct cpu_user_regs_x86_32 *cp)
601 {
602 cp->ebx = rp->ebx;
603 cp->ecx = rp->ecx;
604 cp->edx = rp->edx;
605 cp->esi = rp->esi;
606 cp->edi = rp->edi;
607 cp->ebp = rp->ebp;
608 cp->eax = rp->eax;
609 cp->eip = rp->eip;
610 cp->esp = rp->esp;
611 cp->cs = rp->cs;
612 cp->ss = rp->ss;
613 cp->es = rp->es;
614 cp->ds = rp->ds;
615 cp->fs = rp->fs;
616 cp->gs = rp->gs;
617 cp->eflags = rp->eflags;
618 }
619
620 static void
_cp_32gdb_to_64ctxt(struct xg_gdb_regs32 * rp,struct cpu_user_regs_x86_64 * cp)621 _cp_32gdb_to_64ctxt(struct xg_gdb_regs32 *rp, struct cpu_user_regs_x86_64 *cp)
622 {
623 cp->rbx = rp->ebx;
624 cp->rcx = rp->ecx;
625 cp->rdx = rp->edx;
626 cp->rsi = rp->esi;
627 cp->rdi = rp->edi;
628 cp->rbp = rp->ebp;
629 cp->rax = rp->eax;
630 cp->rip = rp->eip;
631 cp->rsp = rp->esp;
632 cp->cs = rp->cs;
633 cp->ss = rp->ss;
634 cp->es = rp->es;
635 cp->ds = rp->ds;
636 cp->fs = rp->fs;
637 cp->gs = rp->gs;
638 cp->rflags = rp->eflags;
639 }
640
641 static void
_cp_64gdb_to_64ctxt(struct xg_gdb_regs64 * rp,struct cpu_user_regs_x86_64 * cp)642 _cp_64gdb_to_64ctxt(struct xg_gdb_regs64 *rp, struct cpu_user_regs_x86_64 *cp)
643 {
644 cp->r8 = rp->r8;
645 cp->r9 = rp->r9;
646 cp->r10 = rp->r10;
647 cp->r11 = rp->r11;
648 cp->r12 = rp->r12;
649 cp->r13 = rp->r13;
650 cp->r14 = rp->r14;
651 cp->r15 = rp->r15;
652 cp->rbx = rp->rbx;
653 cp->rcx = rp->rcx;
654 cp->rdx = rp->rdx;
655 cp->rsi = rp->rsi;
656 cp->rdi = rp->rdi;
657 cp->rbp = rp->rbp;
658 cp->rax = rp->rax;
659 cp->rip = rp->rip;
660 cp->rsp = rp->rsp;
661 cp->rflags = rp->rflags;
662
663 cp->cs = (uint16_t)rp->cs;
664 cp->ss = (uint16_t)rp->ss;
665 cp->es = (uint16_t)rp->es;
666 cp->ds = (uint16_t)rp->ds;
667 cp->fs = (uint16_t)rp->fs;
668 cp->gs = (uint16_t)rp->gs;
669 }
670
671
672 /* get vcpu context from xen and return it in *ctxtp
673 * RETURNS: 0 for success
674 */
675 static int
_get_vcpu_ctxt(vcpuid_t vcpu_id,union vcpu_guest_context_any * anycp)676 _get_vcpu_ctxt(vcpuid_t vcpu_id, union vcpu_guest_context_any *anycp)
677 {
678 int sz = sizeof(union vcpu_guest_context_any);
679
680 memset(anycp, 0, sz);
681 domctl.u.vcpucontext.vcpu = (uint16_t)vcpu_id;
682 set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &anycp->ctxt);
683
684 if (_domctl_hcall(XEN_DOMCTL_getvcpucontext, anycp, sz)) {
685 XGERR("Failed hcall to get vcpu ctxt. errno:%d\n", errno);
686 return 1;
687 }
688 return 0;
689 }
690
691 /*
692 * read regs for a particular vcpu. For now only GPRs, no FPRs.
693 * Returns: 0 success, else failure with errno set
694 */
695 int
xg_regs_read(regstype_t which_regs,vcpuid_t which_vcpu,union xg_gdb_regs * regsp,int guest_bitness)696 xg_regs_read(regstype_t which_regs, vcpuid_t which_vcpu,
697 union xg_gdb_regs *regsp, int guest_bitness)
698 {
699 union vcpu_guest_context_any anyc;
700 struct cpu_user_regs_x86_32 *cr32p = &anyc.ctxt32.user_regs;
701 struct cpu_user_regs_x86_64 *cr64p = &anyc.ctxt64.user_regs;
702 struct xg_gdb_regs32 *r32p = ®sp->gregs_32;
703 struct xg_gdb_regs64 *r64p = ®sp->gregs_64;
704 int rc;
705
706 if (which_regs != XG_GPRS) {
707 errno = EINVAL;
708 XGERR("regs got: %d. Expected GPRS:%d\n", which_regs, XG_GPRS);
709 return 1;
710 }
711 if ((rc=_get_vcpu_ctxt(which_vcpu, &anyc)))
712 return rc;
713
714 /* 64bit hyp: only 32bit PV returns 32bit context, all others 64bit.
715 * 32bit hyp: all contexts returned are 32bit */
716 if (guest_bitness == 32) {
717 if (_32bit_hyp || !_hvm_guest)
718 _cp_32ctxt_to_32gdb(cr32p, r32p);
719 else
720 _cp_64ctxt_to_32gdb(cr64p, r32p);
721 } else
722 _cp_64ctxt_to_64gdb(cr64p, r64p);
723
724 XGTRC("X:vcpu:%d bitness:%d rc:%d\n", which_vcpu, guest_bitness, rc);
725 return rc;
726 }
727
728 /*
729 * write registers for the given vcpu
730 * Returns: 0 success, 1 failure with errno
731 */
732 int
xg_regs_write(regstype_t which_regs,vcpuid_t which_vcpu,union xg_gdb_regs * regsp,int guest_bitness)733 xg_regs_write(regstype_t which_regs, vcpuid_t which_vcpu,
734 union xg_gdb_regs *regsp, int guest_bitness)
735 {
736 union vcpu_guest_context_any anyc;
737 struct cpu_user_regs_x86_32 *cr32p = &anyc.ctxt32.user_regs;
738 struct cpu_user_regs_x86_64 *cr64p = &anyc.ctxt64.user_regs;
739 struct xg_gdb_regs32 *r32p = ®sp->gregs_32;
740 struct xg_gdb_regs64 *r64p = ®sp->gregs_64;
741 int rc, sz = sizeof(anyc);
742
743 if (which_regs != XG_GPRS) {
744 errno = EINVAL;
745 XGERR("regs got: %d. Expected GPRS:%d\n", which_regs, XG_GPRS);
746 return 1;
747 }
748 if ((rc=_get_vcpu_ctxt(which_vcpu, &anyc)))
749 return rc;
750
751 if (guest_bitness == 32) {
752 if (_32bit_hyp || !_hvm_guest)
753 _cp_32gdb_to_32ctxt(r32p, cr32p);
754 else
755 _cp_32gdb_to_64ctxt(r32p, cr64p);
756 } else
757 _cp_64gdb_to_64ctxt(r64p, cr64p);
758
759 /* set vcpu context back */
760 if ((rc =_domctl_hcall(XEN_DOMCTL_setvcpucontext, &anyc, sz))) {
761 XGERR("Failed hcall to set vcpu ctxt. errno:%d\n", errno);
762 return rc;
763 }
764 XGTRC("X:vcpu:%d bitness:%d rc:%d\n", which_vcpu, guest_bitness, rc);
765 return rc;
766 }
767
768 /*
769 * Returns: bytes remaining to be read. 0 => read all bytes, ie, success.
770 */
771 int
xg_read_mem(uint64_t guestva,char * tobuf,int tobuf_len,uint64_t pgd3val)772 xg_read_mem(uint64_t guestva, char *tobuf, int tobuf_len, uint64_t pgd3val)
773 {
774 struct xen_domctl_gdbsx_memio *iop = &domctl.u.gdbsx_guest_memio;
775 union {uint64_t llbuf8; char buf8[8];} u = {0};
776 int i, rc;
777
778 XGTRC("E:gva:%llx tobuf:%lx len:%d\n", guestva, tobuf, tobuf_len);
779
780 memset(&domctl.u, 0, sizeof(domctl.u));
781 iop->pgd3val = pgd3val;
782 iop->gva = guestva;
783 iop->uva = (uint64_aligned_t)((unsigned long)tobuf);
784 iop->len = tobuf_len;
785 iop->gwr = 0; /* not writing to guest */
786
787 if ( (rc = _domctl_hcall(XEN_DOMCTL_gdbsx_guestmemio, tobuf, tobuf_len)) )
788 {
789 XGTRC("ERROR: failed to read bytes. errno:%d rc:%d\n", errno, rc);
790 return tobuf_len;
791 }
792
793 for(i=0; i < XGMIN(8, tobuf_len); u.buf8[i]=tobuf[i], i++);
794 XGTRC("X:remain:%d buf8:0x%llx\n", iop->remain, u.llbuf8);
795
796 return iop->remain;
797 }
798
799 /*
800 * Returns: bytes that could not be written. 0 => wrote all bytes, ie, success.
801 */
802 int
xg_write_mem(uint64_t guestva,char * frombuf,int buflen,uint64_t pgd3val)803 xg_write_mem(uint64_t guestva, char *frombuf, int buflen, uint64_t pgd3val)
804 {
805 struct xen_domctl_gdbsx_memio *iop = &domctl.u.gdbsx_guest_memio;
806 union {uint64_t llbuf8; char buf8[8];} u = {0};
807 int i, rc;
808
809 for(i=0; i < XGMIN(8, buflen); u.buf8[i]=frombuf[i], i++);
810 XGTRC("E:gva:%llx frombuf:%lx len:%d buf8:0x%llx\n", guestva, frombuf,
811 buflen, u.llbuf8);
812
813 memset(&domctl.u, 0, sizeof(domctl.u));
814 iop->pgd3val = pgd3val;
815 iop->gva = guestva;
816 iop->uva = (uint64_aligned_t)((unsigned long)frombuf);
817 iop->len = buflen;
818 iop->gwr = 1; /* writing to guest */
819
820 if ((rc=_domctl_hcall(XEN_DOMCTL_gdbsx_guestmemio, frombuf, buflen)))
821 {
822 XGERR("ERROR: failed to write bytes to %llx. errno:%d rc:%d\n",
823 guestva, errno, rc);
824 return buflen;
825 }
826 return iop->remain;
827 }
828
829 /*
830 * Local variables:
831 * mode: C
832 * c-file-style: "BSD"
833 * c-basic-offset: 4
834 * indent-tabs-mode: nil
835 * End:
836 */
837