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 = &regsp->gregs_32;
703     struct xg_gdb_regs64 *r64p = &regsp->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 = &regsp->gregs_32;
740     struct xg_gdb_regs64 *r64p = &regsp->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