Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / unisys / visorchipset / parser.c
1 /* parser.c
2  *
3  * Copyright (C) 2010 - 2013 UNISYS CORPORATION
4  * All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or (at
9  * your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14  * NON INFRINGEMENT.  See the GNU General Public License for more
15  * details.
16  */
17
18 #include "parser.h"
19 #include "memregion.h"
20 #include "controlvmchannel.h"
21 #include <linux/ctype.h>
22 #include <linux/mm.h>
23 #include <linux/uuid.h>
24
25 #define MYDRVNAME "visorchipset_parser"
26 #define CURRENT_FILE_PC VISOR_CHIPSET_PC_parser_c
27
28 /* We will refuse to allocate more than this many bytes to copy data from
29  * incoming payloads.  This serves as a throttling mechanism.
30  */
31 #define MAX_CONTROLVM_PAYLOAD_BYTES (1024*128)
32 static ulong controlvm_payload_bytes_buffered;
33
34 struct parser_context {
35         ulong allocbytes;
36         ulong param_bytes;
37         u8 *curr;
38         ulong bytes_remaining;
39         BOOL byte_stream;
40         char data[0];
41 };
42
43 static struct parser_context *
44 parser_init_guts(u64 addr, u32 bytes, BOOL local,
45                  BOOL standard_payload_header, BOOL *retry)
46 {
47         int allocbytes = sizeof(struct parser_context) + bytes;
48         struct parser_context *rc = NULL;
49         struct parser_context *ctx = NULL;
50         struct memregion *rgn = NULL;
51         struct spar_controlvm_parameters_header *phdr = NULL;
52
53         if (retry)
54                 *retry = FALSE;
55         if (!standard_payload_header)
56                 /* alloc and 0 extra byte to ensure payload is
57                  * '\0'-terminated
58                  */
59                 allocbytes++;
60         if ((controlvm_payload_bytes_buffered + bytes)
61             > MAX_CONTROLVM_PAYLOAD_BYTES) {
62                 if (retry)
63                         *retry = TRUE;
64                 rc = NULL;
65                 goto cleanup;
66         }
67         ctx = kzalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY);
68         if (!ctx) {
69                 if (retry)
70                         *retry = TRUE;
71                 rc = NULL;
72                 goto cleanup;
73         }
74
75         ctx->allocbytes = allocbytes;
76         ctx->param_bytes = bytes;
77         ctx->curr = NULL;
78         ctx->bytes_remaining = 0;
79         ctx->byte_stream = FALSE;
80         if (local) {
81                 void *p;
82
83                 if (addr > virt_to_phys(high_memory - 1)) {
84                         rc = NULL;
85                         goto cleanup;
86                 }
87                 p = __va((ulong) (addr));
88                 memcpy(ctx->data, p, bytes);
89         } else {
90                 rgn = visor_memregion_create(addr, bytes);
91                 if (!rgn) {
92                         rc = NULL;
93                         goto cleanup;
94                 }
95                 if (visor_memregion_read(rgn, 0, ctx->data, bytes) < 0) {
96                         rc = NULL;
97                         goto cleanup;
98                 }
99         }
100         if (!standard_payload_header) {
101                 ctx->byte_stream = TRUE;
102                 rc = ctx;
103                 goto cleanup;
104         }
105         phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
106         if (phdr->total_length != bytes) {
107                 rc = NULL;
108                 goto cleanup;
109         }
110         if (phdr->total_length < phdr->header_length) {
111                 rc = NULL;
112                 goto cleanup;
113         }
114         if (phdr->header_length <
115             sizeof(struct spar_controlvm_parameters_header)) {
116                 rc = NULL;
117                 goto cleanup;
118         }
119
120         rc = ctx;
121 cleanup:
122         if (rgn) {
123                 visor_memregion_destroy(rgn);
124                 rgn = NULL;
125         }
126         if (rc) {
127                 controlvm_payload_bytes_buffered += ctx->param_bytes;
128         } else {
129                 if (ctx) {
130                         parser_done(ctx);
131                         ctx = NULL;
132                 }
133         }
134         return rc;
135 }
136
137 struct parser_context *
138 parser_init(u64 addr, u32 bytes, BOOL local, BOOL *retry)
139 {
140         return parser_init_guts(addr, bytes, local, TRUE, retry);
141 }
142
143 /* Call this instead of parser_init() if the payload area consists of just
144  * a sequence of bytes, rather than a struct spar_controlvm_parameters_header
145  * structures.  Afterwards, you can call parser_simpleString_get() or
146  * parser_byteStream_get() to obtain the data.
147  */
148 struct parser_context *
149 parser_init_byte_stream(u64 addr, u32 bytes, BOOL local, BOOL *retry)
150 {
151         return parser_init_guts(addr, bytes, local, FALSE, retry);
152 }
153
154 /* Obtain '\0'-terminated copy of string in payload area.
155  */
156 char *
157 parser_simpleString_get(struct parser_context *ctx)
158 {
159         if (!ctx->byte_stream)
160                 return NULL;
161         return ctx->data;       /* note this IS '\0'-terminated, because of
162                                  * the num of bytes we alloc+clear in
163                                  * parser_init_byteStream() */
164 }
165
166 /* Obtain a copy of the buffer in the payload area.
167  */
168 void *parser_byte_stream_get(struct parser_context *ctx, ulong *nbytes)
169 {
170         if (!ctx->byte_stream)
171                 return NULL;
172         if (nbytes)
173                 *nbytes = ctx->param_bytes;
174         return (void *)ctx->data;
175 }
176
177 uuid_le
178 parser_id_get(struct parser_context *ctx)
179 {
180         struct spar_controlvm_parameters_header *phdr = NULL;
181
182         if (ctx == NULL)
183                 return NULL_UUID_LE;
184         phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
185         return phdr->id;
186 }
187
188 void
189 parser_param_start(struct parser_context *ctx, PARSER_WHICH_STRING which_string)
190 {
191         struct spar_controlvm_parameters_header *phdr = NULL;
192
193         if (ctx == NULL)
194                 goto Away;
195         phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
196         switch (which_string) {
197         case PARSERSTRING_INITIATOR:
198                 ctx->curr = ctx->data + phdr->initiator_offset;
199                 ctx->bytes_remaining = phdr->initiator_length;
200                 break;
201         case PARSERSTRING_TARGET:
202                 ctx->curr = ctx->data + phdr->target_offset;
203                 ctx->bytes_remaining = phdr->target_length;
204                 break;
205         case PARSERSTRING_CONNECTION:
206                 ctx->curr = ctx->data + phdr->connection_offset;
207                 ctx->bytes_remaining = phdr->connection_length;
208                 break;
209         case PARSERSTRING_NAME:
210                 ctx->curr = ctx->data + phdr->name_offset;
211                 ctx->bytes_remaining = phdr->name_length;
212                 break;
213         default:
214                 break;
215         }
216
217 Away:
218         return;
219 }
220
221 void
222 parser_done(struct parser_context *ctx)
223 {
224         if (!ctx)
225                 return;
226         controlvm_payload_bytes_buffered -= ctx->param_bytes;
227         kfree(ctx);
228 }
229
230 /** Return length of string not counting trailing spaces. */
231 static int
232 string_length_no_trail(char *s, int len)
233 {
234         int i = len - 1;
235
236         while (i >= 0) {
237                 if (!isspace(s[i]))
238                         return i + 1;
239                 i--;
240         }
241         return 0;
242 }
243
244 /** Grab the next name and value out of the parameter buffer.
245  *  The entire parameter buffer looks like this:
246  *      <name>=<value>\0
247  *      <name>=<value>\0
248  *      ...
249  *      \0
250  *  If successful, the next <name> value is returned within the supplied
251  *  <nam> buffer (the value is always upper-cased), and the corresponding
252  *  <value> is returned within a kmalloc()ed buffer, whose pointer is
253  *  provided as the return value of this function.
254  *  (The total number of bytes allocated is strlen(<value>)+1.)
255  *
256  *  NULL is returned to indicate failure, which can occur for several reasons:
257  *  - all <name>=<value> pairs have already been processed
258  *  - bad parameter
259  *  - parameter buffer ends prematurely (couldn't find an '=' or '\0' within
260  *    the confines of the parameter buffer)
261  *  - the <nam> buffer is not large enough to hold the <name> of the next
262  *    parameter
263  */
264 void *
265 parser_param_get(struct parser_context *ctx, char *nam, int namesize)
266 {
267         u8 *pscan, *pnam = nam;
268         ulong nscan;
269         int value_length = -1, orig_value_length = -1;
270         void *value = NULL;
271         int i;
272         int closing_quote = 0;
273
274         if (!ctx)
275                 return NULL;
276         pscan = ctx->curr;
277         nscan = ctx->bytes_remaining;
278         if (nscan == 0)
279                 return NULL;
280         if (*pscan == '\0')
281                 /*  This is the normal return point after you have processed
282                  *  all of the <name>=<value> pairs in a syntactically-valid
283                  *  parameter buffer.
284                  */
285                 return NULL;
286
287         /* skip whitespace */
288         while (isspace(*pscan)) {
289                 pscan++;
290                 nscan--;
291                 if (nscan == 0)
292                         return NULL;
293         }
294
295         while (*pscan != ':') {
296                 if (namesize <= 0)
297                         return NULL;
298                 *pnam = toupper(*pscan);
299                 pnam++;
300                 namesize--;
301                 pscan++;
302                 nscan--;
303                 if (nscan == 0)
304                         return NULL;
305         }
306         if (namesize <= 0)
307                 return NULL;
308         *pnam = '\0';
309         nam[string_length_no_trail(nam, strlen(nam))] = '\0';
310
311         /* point to char immediately after ":" in "<name>:<value>" */
312         pscan++;
313         nscan--;
314         /* skip whitespace */
315         while (isspace(*pscan)) {
316                 pscan++;
317                 nscan--;
318                 if (nscan == 0)
319                         return NULL;
320         }
321         if (nscan == 0)
322                 return NULL;
323         if (*pscan == '\'' || *pscan == '"') {
324                 closing_quote = *pscan;
325                 pscan++;
326                 nscan--;
327                 if (nscan == 0)
328                         return NULL;
329         }
330
331         /* look for a separator character, terminator character, or
332          * end of data
333          */
334         for (i = 0, value_length = -1; i < nscan; i++) {
335                 if (closing_quote) {
336                         if (pscan[i] == '\0')
337                                 return NULL;
338                         if (pscan[i] == closing_quote) {
339                                 value_length = i;
340                                 break;
341                         }
342                 } else
343                     if (pscan[i] == ',' || pscan[i] == ';'
344                         || pscan[i] == '\0') {
345                         value_length = i;
346                         break;
347                 }
348         }
349         if (value_length < 0) {
350                 if (closing_quote)
351                         return NULL;
352                 value_length = nscan;
353         }
354         orig_value_length = value_length;
355         if (closing_quote == 0)
356                 value_length = string_length_no_trail(pscan, orig_value_length);
357         value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
358         if (value == NULL)
359                 return NULL;
360         memcpy(value, pscan, value_length);
361         ((u8 *) (value))[value_length] = '\0';
362
363         pscan += orig_value_length;
364         nscan -= orig_value_length;
365
366         /* skip past separator or closing quote */
367         if (nscan > 0) {
368                 if (*pscan != '\0') {
369                         pscan++;
370                         nscan--;
371                 }
372         }
373
374         if (closing_quote && (nscan > 0)) {
375                 /* we still need to skip around the real separator if present */
376                 /* first, skip whitespace */
377                 while (isspace(*pscan)) {
378                         pscan++;
379                         nscan--;
380                         if (nscan == 0)
381                                 break;
382                 }
383                 if (nscan > 0) {
384                         if (*pscan == ',' || *pscan == ';') {
385                                 pscan++;
386                                 nscan--;
387                         } else if (*pscan != '\0') {
388                                 kfree(value);
389                                 value = NULL;
390                                 return NULL;
391                         }
392                 }
393         }
394         ctx->curr = pscan;
395         ctx->bytes_remaining = nscan;
396         return value;
397 }
398
399 void *
400 parser_string_get(struct parser_context *ctx)
401 {
402         u8 *pscan;
403         ulong nscan;
404         int value_length = -1;
405         void *value = NULL;
406         int i;
407
408         if (!ctx)
409                 return NULL;
410         pscan = ctx->curr;
411         nscan = ctx->bytes_remaining;
412         if (nscan == 0)
413                 return NULL;
414         if (!pscan)
415                 return NULL;
416         for (i = 0, value_length = -1; i < nscan; i++)
417                 if (pscan[i] == '\0') {
418                         value_length = i;
419                         break;
420                 }
421         if (value_length < 0)   /* '\0' was not included in the length */
422                 value_length = nscan;
423         value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
424         if (value == NULL)
425                 return NULL;
426         if (value_length > 0)
427                 memcpy(value, pscan, value_length);
428         ((u8 *) (value))[value_length] = '\0';
429         return value;
430 }