1 #include "libxl_osdeps.h" /* must come before any other headers */
2 #include "libxlu_internal.h"
3 #include "libxlu_disk_l.h"
4 #include "libxlu_disk_i.h"
5 #include "libxlu_cfg_i.h"
6 
7 
8 #define XLU__PCI_ERR(_c, _x, _a...) \
9     if((_c) && (_c)->report) fprintf((_c)->report, _x, ##_a)
10 
hex_convert(const char * str,unsigned int * val,unsigned int mask)11 static int hex_convert(const char *str, unsigned int *val, unsigned int mask)
12 {
13     unsigned long ret;
14     char *end;
15 
16     ret = strtoul(str, &end, 16);
17     if ( end == str || *end != '\0' )
18         return -1;
19     if ( ret & ~mask )
20         return -1;
21     *val = (unsigned int)ret & mask;
22     return 0;
23 }
24 
pcidev_struct_fill(libxl_device_pci * pcidev,unsigned int domain,unsigned int bus,unsigned int dev,unsigned int func,unsigned int vdevfn)25 static int pcidev_struct_fill(libxl_device_pci *pcidev, unsigned int domain,
26                                unsigned int bus, unsigned int dev,
27                                unsigned int func, unsigned int vdevfn)
28 {
29     pcidev->domain = domain;
30     pcidev->bus = bus;
31     pcidev->dev = dev;
32     pcidev->func = func;
33     pcidev->vdevfn = vdevfn;
34     return 0;
35 }
36 
37 #define STATE_DOMAIN    0
38 #define STATE_BUS       1
39 #define STATE_DEV       2
40 #define STATE_FUNC      3
41 #define STATE_VSLOT     4
42 #define STATE_OPTIONS_K 6
43 #define STATE_OPTIONS_V 7
44 #define STATE_TERMINAL  8
45 #define STATE_TYPE      9
46 #define STATE_RDM_STRATEGY      10
47 #define STATE_RESERVE_POLICY    11
48 #define INVALID         0xffffffff
xlu_pci_parse_bdf(XLU_Config * cfg,libxl_device_pci * pcidev,const char * str)49 int xlu_pci_parse_bdf(XLU_Config *cfg, libxl_device_pci *pcidev, const char *str)
50 {
51     unsigned state = STATE_DOMAIN;
52     unsigned dom = INVALID, bus = INVALID, dev = INVALID, func = INVALID, vslot = 0;
53     char *buf2, *tok, *ptr, *end, *optkey = NULL;
54 
55     if ( NULL == (buf2 = ptr = strdup(str)) )
56         return ERROR_NOMEM;
57 
58     for(tok = ptr, end = ptr + strlen(ptr) + 1; ptr < end; ptr++) {
59         switch(state) {
60         case STATE_DOMAIN:
61             if ( *ptr == ':' ) {
62                 state = STATE_BUS;
63                 *ptr = '\0';
64                 if ( hex_convert(tok, &dom, 0xffff) )
65                     goto parse_error;
66                 tok = ptr + 1;
67             }
68             break;
69         case STATE_BUS:
70             if ( *ptr == ':' ) {
71                 state = STATE_DEV;
72                 *ptr = '\0';
73                 if ( hex_convert(tok, &bus, 0xff) )
74                     goto parse_error;
75                 tok = ptr + 1;
76             }else if ( *ptr == '.' ) {
77                 state = STATE_FUNC;
78                 *ptr = '\0';
79                 if ( dom & ~0xff )
80                     goto parse_error;
81                 bus = dom;
82                 dom = 0;
83                 if ( hex_convert(tok, &dev, 0xff) )
84                     goto parse_error;
85                 tok = ptr + 1;
86             }
87             break;
88         case STATE_DEV:
89             if ( *ptr == '.' ) {
90                 state = STATE_FUNC;
91                 *ptr = '\0';
92                 if ( hex_convert(tok, &dev, 0xff) )
93                     goto parse_error;
94                 tok = ptr + 1;
95             }
96             break;
97         case STATE_FUNC:
98             if ( *ptr == '\0' || *ptr == '@' || *ptr == ',' ) {
99                 switch( *ptr ) {
100                 case '\0':
101                     state = STATE_TERMINAL;
102                     break;
103                 case '@':
104                     state = STATE_VSLOT;
105                     break;
106                 case ',':
107                     state = STATE_OPTIONS_K;
108                     break;
109                 }
110                 *ptr = '\0';
111                 if ( !strcmp(tok, "*") ) {
112                     pcidev->vfunc_mask = LIBXL_PCI_FUNC_ALL;
113                 }else{
114                     if ( hex_convert(tok, &func, 0x7) )
115                         goto parse_error;
116                     pcidev->vfunc_mask = (1 << 0);
117                 }
118                 tok = ptr + 1;
119             }
120             break;
121         case STATE_VSLOT:
122             if ( *ptr == '\0' || *ptr == ',' ) {
123                 state = ( *ptr == ',' ) ? STATE_OPTIONS_K : STATE_TERMINAL;
124                 *ptr = '\0';
125                 if ( hex_convert(tok, &vslot, 0xff) )
126                     goto parse_error;
127                 tok = ptr + 1;
128             }
129             break;
130         case STATE_OPTIONS_K:
131             if ( *ptr == '=' ) {
132                 state = STATE_OPTIONS_V;
133                 *ptr = '\0';
134                 optkey = tok;
135                 tok = ptr + 1;
136             }
137             break;
138         case STATE_OPTIONS_V:
139             if ( *ptr == ',' || *ptr == '\0' ) {
140                 state = (*ptr == ',') ? STATE_OPTIONS_K : STATE_TERMINAL;
141                 *ptr = '\0';
142                 if ( !strcmp(optkey, "msitranslate") ) {
143                     pcidev->msitranslate = atoi(tok);
144                 }else if ( !strcmp(optkey, "power_mgmt") ) {
145                     pcidev->power_mgmt = atoi(tok);
146                 }else if ( !strcmp(optkey, "permissive") ) {
147                     pcidev->permissive = atoi(tok);
148                 }else if ( !strcmp(optkey, "seize") ) {
149                     pcidev->seize = atoi(tok);
150                 } else if (!strcmp(optkey, "rdm_policy")) {
151                     if (!strcmp(tok, "strict")) {
152                         pcidev->rdm_policy = LIBXL_RDM_RESERVE_POLICY_STRICT;
153                     } else if (!strcmp(tok, "relaxed")) {
154                         pcidev->rdm_policy = LIBXL_RDM_RESERVE_POLICY_RELAXED;
155                     } else {
156                         XLU__PCI_ERR(cfg, "%s is not an valid PCI RDM property"
157                                           " policy: 'strict' or 'relaxed'.",
158                                      tok);
159                         goto parse_error;
160                     }
161                 } else {
162                     XLU__PCI_ERR(cfg, "Unknown PCI BDF option: %s", optkey);
163                 }
164                 tok = ptr + 1;
165             }
166         default:
167             break;
168         }
169     }
170 
171     if ( tok != ptr || state != STATE_TERMINAL )
172         goto parse_error;
173 
174     assert(dom != INVALID && bus != INVALID && dev != INVALID && func != INVALID);
175 
176     /* Just a pretty way to fill in the values */
177     pcidev_struct_fill(pcidev, dom, bus, dev, func, vslot << 3);
178 
179     free(buf2);
180 
181     return 0;
182 
183 parse_error:
184     free(buf2);
185     return ERROR_INVAL;
186 }
187 
xlu_rdm_parse(XLU_Config * cfg,libxl_rdm_reserve * rdm,const char * str)188 int xlu_rdm_parse(XLU_Config *cfg, libxl_rdm_reserve *rdm, const char *str)
189 {
190     unsigned state = STATE_TYPE;
191     char *buf2, *tok, *ptr, *end;
192 
193     if (NULL == (buf2 = ptr = strdup(str)))
194         return ERROR_NOMEM;
195 
196     for (tok = ptr, end = ptr + strlen(ptr) + 1; ptr < end; ptr++) {
197         switch(state) {
198         case STATE_TYPE:
199             if (*ptr == '=') {
200                 *ptr = '\0';
201                 if (!strcmp(tok, "strategy")) {
202                     state = STATE_RDM_STRATEGY;
203                 } else if (!strcmp(tok, "policy")) {
204                     state = STATE_RESERVE_POLICY;
205                 } else {
206                     XLU__PCI_ERR(cfg, "Unknown RDM state option: %s", tok);
207                     goto parse_error;
208                 }
209                 tok = ptr + 1;
210             }
211             break;
212         case STATE_RDM_STRATEGY:
213             if (*ptr == '\0' || *ptr == ',') {
214                 state = *ptr == ',' ? STATE_TYPE : STATE_TERMINAL;
215                 *ptr = '\0';
216                 if (!strcmp(tok, "host")) {
217                     rdm->strategy = LIBXL_RDM_RESERVE_STRATEGY_HOST;
218                 } else {
219                     XLU__PCI_ERR(cfg, "Unknown RDM strategy option: %s", tok);
220                     goto parse_error;
221                 }
222                 tok = ptr + 1;
223             }
224             break;
225         case STATE_RESERVE_POLICY:
226             if (*ptr == ',' || *ptr == '\0') {
227                 state = *ptr == ',' ? STATE_TYPE : STATE_TERMINAL;
228                 *ptr = '\0';
229                 if (!strcmp(tok, "strict")) {
230                     rdm->policy = LIBXL_RDM_RESERVE_POLICY_STRICT;
231                 } else if (!strcmp(tok, "relaxed")) {
232                     rdm->policy = LIBXL_RDM_RESERVE_POLICY_RELAXED;
233                 } else {
234                     XLU__PCI_ERR(cfg, "Unknown RDM property policy value: %s",
235                                  tok);
236                     goto parse_error;
237                 }
238                 tok = ptr + 1;
239             }
240         default:
241             break;
242         }
243     }
244 
245     if (tok != ptr || state != STATE_TERMINAL)
246         goto parse_error;
247 
248     free(buf2);
249 
250     return 0;
251 
252 parse_error:
253     free(buf2);
254     return ERROR_INVAL;
255 }
256 
257 /*
258  * Local variables:
259  * mode: C
260  * c-basic-offset: 4
261  * indent-tabs-mode: nil
262  * End:
263  */
264