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