1 /*
2 * Copyright 2009-2017 Citrix Ltd and other contributors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include <stdlib.h>
16
17 #include <libxl.h>
18 #include <libxl_utils.h>
19 #include <libxlutil.h>
20
21 #include "xl.h"
22 #include "xl_utils.h"
23 #include "xl_parse.h"
24
pcilist(uint32_t domid)25 static void pcilist(uint32_t domid)
26 {
27 libxl_device_pci *pcis;
28 int num, i;
29
30 pcis = libxl_device_pci_list(ctx, domid, &num);
31 if (pcis == NULL)
32 return;
33 printf("Vdev Device\n");
34 for (i = 0; i < num; i++) {
35 printf("%02x.%01x %04x:%02x:%02x.%01x\n",
36 (pcis[i].vdevfn >> 3) & 0x1f, pcis[i].vdevfn & 0x7,
37 pcis[i].domain, pcis[i].bus, pcis[i].dev, pcis[i].func);
38 }
39 libxl_device_pci_list_free(pcis, num);
40 }
41
main_pcilist(int argc,char ** argv)42 int main_pcilist(int argc, char **argv)
43 {
44 uint32_t domid;
45 int opt;
46
47 SWITCH_FOREACH_OPT(opt, "", NULL, "pci-list", 1) {
48 /* No options */
49 }
50
51 domid = find_domain(argv[optind]);
52
53 pcilist(domid);
54 return 0;
55 }
56
pcidetach(uint32_t domid,const char * spec_string,int force)57 static int pcidetach(uint32_t domid, const char *spec_string, int force)
58 {
59 libxl_device_pci pci;
60 XLU_Config *config;
61 int r = 0;
62
63 libxl_device_pci_init(&pci);
64
65 config = xlu_cfg_init(stderr, "command line");
66 if (!config) { perror("xlu_cfg_inig"); exit(-1); }
67
68 if (xlu_pci_parse_spec_string(config, &pci, spec_string)) {
69 fprintf(stderr, "pci-detach: malformed PCI_SPEC_STRING \"%s\"\n",
70 spec_string);
71 exit(2);
72 }
73 if (force) {
74 if (libxl_device_pci_destroy(ctx, domid, &pci, 0))
75 r = 1;
76 } else {
77 if (libxl_device_pci_remove(ctx, domid, &pci, 0))
78 r = 1;
79 }
80
81 libxl_device_pci_dispose(&pci);
82 xlu_cfg_destroy(config);
83
84 return r;
85 }
86
main_pcidetach(int argc,char ** argv)87 int main_pcidetach(int argc, char **argv)
88 {
89 uint32_t domid;
90 int opt;
91 int force = 0;
92 const char *spec_string = NULL;
93
94 SWITCH_FOREACH_OPT(opt, "f", NULL, "pci-detach", 2) {
95 case 'f':
96 force = 1;
97 break;
98 }
99
100 domid = find_domain(argv[optind]);
101 spec_string = argv[optind + 1];
102
103 if (pcidetach(domid, spec_string, force))
104 return EXIT_FAILURE;
105
106 return EXIT_SUCCESS;
107 }
108
pciattach(uint32_t domid,const char * spec_string)109 static int pciattach(uint32_t domid, const char *spec_string)
110 {
111 libxl_device_pci pci;
112 XLU_Config *config;
113 int r = 0;
114
115 libxl_device_pci_init(&pci);
116
117 config = xlu_cfg_init(stderr, "command line");
118 if (!config) { perror("xlu_cfg_inig"); exit(-1); }
119
120 if (xlu_pci_parse_spec_string(config, &pci, spec_string)) {
121 fprintf(stderr, "pci-attach: malformed PCI_SPEC_STRING \"%s\"\n",
122 spec_string);
123 exit(2);
124 }
125
126 if (libxl_device_pci_add(ctx, domid, &pci, 0))
127 r = 1;
128
129 libxl_device_pci_dispose(&pci);
130 xlu_cfg_destroy(config);
131
132 return r;
133 }
134
main_pciattach(int argc,char ** argv)135 int main_pciattach(int argc, char **argv)
136 {
137 uint32_t domid;
138 int opt;
139 const char *spec_string = NULL;
140
141 SWITCH_FOREACH_OPT(opt, "", NULL, "pci-attach", 2) {
142 /* No options */
143 }
144
145 domid = find_domain(argv[optind]);
146 spec_string = argv[optind + 1];
147
148 if (pciattach(domid, spec_string))
149 return EXIT_FAILURE;
150
151 return EXIT_SUCCESS;
152 }
153
pciassignable_list(bool show_names)154 static void pciassignable_list(bool show_names)
155 {
156 libxl_device_pci *pcis;
157 int num, i;
158
159 pcis = libxl_device_pci_assignable_list(ctx, &num);
160
161 if ( pcis == NULL )
162 return;
163 for (i = 0; i < num; i++) {
164 libxl_device_pci *pci = &pcis[i];
165 char *name = show_names ? pci->name : NULL;
166
167 printf("%04x:%02x:%02x.%01x %s\n",
168 pci->domain, pci->bus, pci->dev, pci->func,
169 name ?: "");
170 }
171 libxl_device_pci_assignable_list_free(pcis, num);
172 }
173
main_pciassignable_list(int argc,char ** argv)174 int main_pciassignable_list(int argc, char **argv)
175 {
176 int opt;
177 static struct option opts[] = {
178 {"show-names", 0, 0, 'n'},
179 COMMON_LONG_OPTS
180 };
181 bool show_names = false;
182
183 SWITCH_FOREACH_OPT(opt, "n", opts, "pci-assignable-list", 0) {
184 case 'n':
185 show_names = true;
186 break;
187 }
188
189 pciassignable_list(show_names);
190 return 0;
191 }
192
pciassignable_add(const char * bdf,const char * name,int rebind)193 static int pciassignable_add(const char *bdf, const char *name, int rebind)
194 {
195 libxl_device_pci pci;
196 XLU_Config *config;
197 int r;
198
199 libxl_device_pci_init(&pci);
200
201 config = xlu_cfg_init(stderr, "command line");
202 if (!config) { perror("xlu_cfg_init"); exit(-1); }
203
204 if (xlu_pci_parse_bdf(config, &pci, bdf)) {
205 fprintf(stderr, "pci-assignable-add: malformed BDF \"%s\"\n", bdf);
206 exit(2);
207 }
208
209 if (name) {
210 pci.name = strdup(name);
211 if (!pci.name) {
212 fprintf(stderr, "pci-assignable-add: memory allocation failure\n");
213 exit(2);
214 }
215 }
216
217 r = libxl_device_pci_assignable_add(ctx, &pci, rebind);
218
219 libxl_device_pci_dispose(&pci);
220 xlu_cfg_destroy(config);
221
222 return r;
223 }
224
main_pciassignable_add(int argc,char ** argv)225 int main_pciassignable_add(int argc, char **argv)
226 {
227 int opt;
228 const char *bdf = NULL;
229 static struct option opts[] = {
230 {"name", 1, 0, 'n'},
231 COMMON_LONG_OPTS
232 };
233 const char *name = NULL;
234
235 SWITCH_FOREACH_OPT(opt, "n:", opts, "pci-assignable-add", 1) {
236 case 'n':
237 name = optarg;
238 break;
239 }
240
241 bdf = argv[optind];
242
243 if (pciassignable_add(bdf, name, 1))
244 return EXIT_FAILURE;
245
246 return EXIT_SUCCESS;
247 }
248
pciassignable_remove(const char * ident,int rebind)249 static int pciassignable_remove(const char *ident, int rebind)
250 {
251 libxl_device_pci pci;
252 XLU_Config *config;
253 int r;
254
255 libxl_device_pci_init(&pci);
256
257 config = xlu_cfg_init(stderr, "command line");
258 if (!config) { perror("xlu_cfg_init"); exit(-1); }
259
260 /* Try remove-by-name first */
261 pci.name = strdup(ident);
262 if (!pci.name) {
263 fprintf(stderr, "pci-assignable-add: memory allocation failure\n");
264 exit(2);
265 }
266
267 r = libxl_device_pci_assignable_remove(ctx, &pci, rebind);
268 if (!r || r != ERROR_NOTFOUND)
269 goto out;
270
271 /* If remove-by-name failed to find the device, try remove-by-BDF */
272 free(pci.name);
273 pci.name = NULL;
274
275 if (xlu_pci_parse_bdf(config, &pci, ident)) {
276 fprintf(stderr,
277 "pci-assignable-remove: malformed BDF '%s'\n", ident);
278 exit(2);
279 }
280
281 r = libxl_device_pci_assignable_remove(ctx, &pci, rebind);
282
283 out:
284 libxl_device_pci_dispose(&pci);
285 xlu_cfg_destroy(config);
286
287 return r;
288 }
289
main_pciassignable_remove(int argc,char ** argv)290 int main_pciassignable_remove(int argc, char **argv)
291 {
292 int opt;
293 const char *ident = NULL;
294 int rebind = 0;
295
296 SWITCH_FOREACH_OPT(opt, "r", NULL, "pci-assignable-remove", 1) {
297 case 'r':
298 rebind=1;
299 break;
300 }
301
302 ident = argv[optind];
303
304 if (pciassignable_remove(ident, rebind))
305 return EXIT_FAILURE;
306
307 return EXIT_SUCCESS;
308 }
309
310 /*
311 * Local variables:
312 * mode: C
313 * c-basic-offset: 4
314 * indent-tabs-mode: nil
315 * End:
316 */
317