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