1 /******************************************************************************
2 *
3 * xc_vm_event.c
4 *
5 * Interface to low-level memory event functionality.
6 *
7 * Copyright (c) 2009 Citrix Systems, Inc. (Patrick Colp)
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "xc_private.h"
24
xc_vm_event_control(xc_interface * xch,uint32_t domain_id,unsigned int op,unsigned int mode,uint32_t * port)25 int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
26 unsigned int mode, uint32_t *port)
27 {
28 DECLARE_DOMCTL;
29 int rc;
30
31 domctl.cmd = XEN_DOMCTL_vm_event_op;
32 domctl.domain = domain_id;
33 domctl.u.vm_event_op.op = op;
34 domctl.u.vm_event_op.mode = mode;
35
36 rc = do_domctl(xch, &domctl);
37 if ( !rc && port )
38 *port = domctl.u.vm_event_op.u.enable.port;
39 return rc;
40 }
41
xc_vm_event_enable(xc_interface * xch,uint32_t domain_id,int param,uint32_t * port)42 void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
43 uint32_t *port)
44 {
45 void *ring_page = NULL;
46 uint64_t pfn;
47 xen_pfn_t ring_pfn, mmap_pfn;
48 unsigned int op, mode;
49 int rc1, rc2, saved_errno;
50
51 if ( !port )
52 {
53 errno = EINVAL;
54 return NULL;
55 }
56
57 /* Pause the domain for ring page setup */
58 rc1 = xc_domain_pause(xch, domain_id);
59 if ( rc1 != 0 )
60 {
61 PERROR("Unable to pause domain\n");
62 return NULL;
63 }
64
65 /* Get the pfn of the ring page */
66 rc1 = xc_hvm_param_get(xch, domain_id, param, &pfn);
67 if ( rc1 != 0 )
68 {
69 PERROR("Failed to get pfn of ring page\n");
70 goto out;
71 }
72
73 ring_pfn = pfn;
74 mmap_pfn = pfn;
75 rc1 = xc_get_pfn_type_batch(xch, domain_id, 1, &mmap_pfn);
76 if ( rc1 || mmap_pfn & XEN_DOMCTL_PFINFO_XTAB )
77 {
78 /* Page not in the physmap, try to populate it */
79 rc1 = xc_domain_populate_physmap_exact(xch, domain_id, 1, 0, 0,
80 &ring_pfn);
81 if ( rc1 != 0 )
82 {
83 PERROR("Failed to populate ring pfn\n");
84 goto out;
85 }
86 }
87
88 mmap_pfn = ring_pfn;
89 ring_page = xc_map_foreign_pages(xch, domain_id, PROT_READ | PROT_WRITE,
90 &mmap_pfn, 1);
91 if ( !ring_page )
92 {
93 PERROR("Could not map the ring page\n");
94 goto out;
95 }
96
97 switch ( param )
98 {
99 case HVM_PARAM_PAGING_RING_PFN:
100 op = XEN_VM_EVENT_ENABLE;
101 mode = XEN_DOMCTL_VM_EVENT_OP_PAGING;
102 break;
103
104 case HVM_PARAM_MONITOR_RING_PFN:
105 op = XEN_VM_EVENT_ENABLE;
106 mode = XEN_DOMCTL_VM_EVENT_OP_MONITOR;
107 break;
108
109 case HVM_PARAM_SHARING_RING_PFN:
110 op = XEN_VM_EVENT_ENABLE;
111 mode = XEN_DOMCTL_VM_EVENT_OP_SHARING;
112 break;
113
114 /*
115 * This is for the outside chance that the HVM_PARAM is valid but is invalid
116 * as far as vm_event goes.
117 */
118 default:
119 errno = EINVAL;
120 rc1 = -1;
121 goto out;
122 }
123
124 rc1 = xc_vm_event_control(xch, domain_id, op, mode, port);
125 if ( rc1 != 0 )
126 {
127 PERROR("Failed to enable vm_event\n");
128 goto out;
129 }
130
131 /* Remove the ring_pfn from the guest's physmap */
132 rc1 = xc_domain_decrease_reservation_exact(xch, domain_id, 1, 0, &ring_pfn);
133 if ( rc1 != 0 )
134 PERROR("Failed to remove ring page from guest physmap");
135
136 out:
137 saved_errno = errno;
138
139 rc2 = xc_domain_unpause(xch, domain_id);
140 if ( rc1 != 0 || rc2 != 0 )
141 {
142 if ( rc2 != 0 )
143 {
144 if ( rc1 == 0 )
145 saved_errno = errno;
146 PERROR("Unable to unpause domain");
147 }
148
149 if ( ring_page )
150 xenforeignmemory_unmap(xch->fmem, ring_page, 1);
151 ring_page = NULL;
152
153 errno = saved_errno;
154 }
155
156 return ring_page;
157 }
158
xc_vm_event_get_version(xc_interface * xch)159 int xc_vm_event_get_version(xc_interface *xch)
160 {
161 DECLARE_DOMCTL;
162 int rc;
163
164 domctl.cmd = XEN_DOMCTL_vm_event_op;
165 domctl.domain = DOMID_INVALID;
166 domctl.u.vm_event_op.op = XEN_VM_EVENT_GET_VERSION;
167 domctl.u.vm_event_op.mode = XEN_DOMCTL_VM_EVENT_OP_MONITOR;
168
169 rc = do_domctl(xch, &domctl);
170 if ( !rc )
171 rc = domctl.u.vm_event_op.u.version;
172 return rc;
173 }
174
175 /*
176 * Local variables:
177 * mode: C
178 * c-file-style: "BSD"
179 * c-basic-offset: 4
180 * tab-width: 4
181 * indent-tabs-mode: nil
182 * End:
183 */
184