diff options
author | Erik Arfvidson <erik.arfvidson@unisys.com> | 2015-05-05 18:36:14 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-05-08 15:26:00 +0200 |
commit | 4616881022a1ea98738966a6cbefab0ea1c085a9 (patch) | |
tree | be4b2cf06e861b4a73326f9df616cc2235ffccc7 /drivers/staging/unisys/visorchipset/visorchipset_main.c | |
parent | staging: unisys: remove file.c and pass functionality to visorchipset (diff) | |
download | linux-dev-4616881022a1ea98738966a6cbefab0ea1c085a9.tar.xz linux-dev-4616881022a1ea98738966a6cbefab0ea1c085a9.zip |
staging: unisys: move parser.[ch] functionality into visorchipset
This patch moves includes files and functions from parser.[ch] into
visorchipset.
Signed-off-by: Erik Arfvidson <erik.arfvidson@unisys.com>
Signed-off-by: Benjamin Romer <benjamin.romer@unisys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/unisys/visorchipset/visorchipset_main.c')
-rw-r--r-- | drivers/staging/unisys/visorchipset/visorchipset_main.c | 411 |
1 files changed, 408 insertions, 3 deletions
diff --git a/drivers/staging/unisys/visorchipset/visorchipset_main.c b/drivers/staging/unisys/visorchipset/visorchipset_main.c index d5bd1a11ad88..dc9f1dc18306 100644 --- a/drivers/staging/unisys/visorchipset/visorchipset_main.c +++ b/drivers/staging/unisys/visorchipset/visorchipset_main.c @@ -15,16 +15,19 @@ * details. */ +#include "memregion.h" +#include "controlvmchannel.h" #include "version.h" #include "procobjecttree.h" #include "visorbus.h" #include "periodic_work.h" -#include "parser.h" #include "uisutils.h" #include "controlvmcompletionstatus.h" #include "guestlinuxdebug.h" #include "visorchipset.h" + +#include <linux/ctype.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/nls.h> @@ -45,6 +48,7 @@ #define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1 #define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100 +#define MAX_CONTROLVM_PAYLOAD_BYTES (1024*128) /* * Module parameters */ @@ -57,6 +61,7 @@ static int visorchipset_clientregwait = 1; /* default is on */ static int visorchipset_testteardown; static int visorchipset_disable_controlvm; static int visorchipset_holdchipsetready; +static unsigned long controlvm_payload_bytes_buffered; static int visorchipset_open(struct inode *inode, struct file *file) @@ -89,6 +94,15 @@ static int clientregistered; #define MAX_CHIPSET_EVENTS 2 static u8 chipset_events[MAX_CHIPSET_EVENTS] = { 0, 0 }; +struct parser_context { + unsigned long allocbytes; + unsigned long param_bytes; + u8 *curr; + unsigned long bytes_remaining; + bool byte_stream; + char data[0]; +}; + static struct delayed_work periodic_controlvm_work; static struct workqueue_struct *periodic_controlvm_workqueue; static DEFINE_SEMAPHORE(notifier_lock); @@ -367,6 +381,397 @@ static void controlvm_respond_physdev_changestate( struct controlvm_message_header *msg_hdr, int response, struct spar_segment_state state); + +static struct parser_context * +parser_init_guts(u64 addr, u32 bytes, bool local, + bool standard_payload_header, bool *retry) +{ + int allocbytes = sizeof(struct parser_context) + bytes; + struct parser_context *rc = NULL; + struct parser_context *ctx = NULL; + struct memregion *rgn = NULL; + struct spar_controlvm_parameters_header *phdr = NULL; + + if (retry) + *retry = false; + if (!standard_payload_header) + /* alloc and 0 extra byte to ensure payload is + * '\0'-terminated + */ + allocbytes++; + if ((controlvm_payload_bytes_buffered + bytes) + > MAX_CONTROLVM_PAYLOAD_BYTES) { + if (retry) + *retry = true; + rc = NULL; + goto cleanup; + } + ctx = kzalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY); + if (!ctx) { + if (retry) + *retry = true; + rc = NULL; + goto cleanup; + } + + ctx->allocbytes = allocbytes; + ctx->param_bytes = bytes; + ctx->curr = NULL; + ctx->bytes_remaining = 0; + ctx->byte_stream = false; + if (local) { + void *p; + + if (addr > virt_to_phys(high_memory - 1)) { + rc = NULL; + goto cleanup; + } + p = __va((unsigned long) (addr)); + memcpy(ctx->data, p, bytes); + } else { + rgn = visor_memregion_create(addr, bytes); + if (!rgn) { + rc = NULL; + goto cleanup; + } + if (visor_memregion_read(rgn, 0, ctx->data, bytes) < 0) { + rc = NULL; + goto cleanup; + } + } + if (!standard_payload_header) { + ctx->byte_stream = true; + rc = ctx; + goto cleanup; + } + phdr = (struct spar_controlvm_parameters_header *)(ctx->data); + if (phdr->total_length != bytes) { + rc = NULL; + goto cleanup; + } + if (phdr->total_length < phdr->header_length) { + rc = NULL; + goto cleanup; + } + if (phdr->header_length < + sizeof(struct spar_controlvm_parameters_header)) { + rc = NULL; + goto cleanup; + } + + rc = ctx; +cleanup: + if (rgn) { + visor_memregion_destroy(rgn); + rgn = NULL; + } + if (rc) { + controlvm_payload_bytes_buffered += ctx->param_bytes; + } else { + if (ctx) { + parser_done(ctx); + ctx = NULL; + } + } + return rc; +} + +struct parser_context * +parser_init(u64 addr, u32 bytes, bool local, bool *retry) +{ + return parser_init_guts(addr, bytes, local, true, retry); +} + +/* Call this instead of parser_init() if the payload area consists of just + * a sequence of bytes, rather than a struct spar_controlvm_parameters_header + * structures. Afterwards, you can call parser_simpleString_get() or + * parser_byteStream_get() to obtain the data. + */ +struct parser_context * +parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry) +{ + return parser_init_guts(addr, bytes, local, false, retry); +} + +/* Obtain '\0'-terminated copy of string in payload area. + */ +char * +parser_simpleString_get(struct parser_context *ctx) +{ + if (!ctx->byte_stream) + return NULL; + return ctx->data; /* note this IS '\0'-terminated, because of + * the num of bytes we alloc+clear in + * parser_init_byteStream() */ +} + +/* Obtain a copy of the buffer in the payload area. + */ +void *parser_byte_stream_get(struct parser_context *ctx, unsigned long *nbytes) +{ + if (!ctx->byte_stream) + return NULL; + if (nbytes) + *nbytes = ctx->param_bytes; + return (void *)ctx->data; +} + +uuid_le +parser_id_get(struct parser_context *ctx) +{ + struct spar_controlvm_parameters_header *phdr = NULL; + + if (ctx == NULL) + return NULL_UUID_LE; + phdr = (struct spar_controlvm_parameters_header *)(ctx->data); + return phdr->id; +} + +void +parser_param_start(struct parser_context *ctx, PARSER_WHICH_STRING which_string) +{ + struct spar_controlvm_parameters_header *phdr = NULL; + + if (ctx == NULL) + goto Away; + phdr = (struct spar_controlvm_parameters_header *)(ctx->data); + switch (which_string) { + case PARSERSTRING_INITIATOR: + ctx->curr = ctx->data + phdr->initiator_offset; + ctx->bytes_remaining = phdr->initiator_length; + break; + case PARSERSTRING_TARGET: + ctx->curr = ctx->data + phdr->target_offset; + ctx->bytes_remaining = phdr->target_length; + break; + case PARSERSTRING_CONNECTION: + ctx->curr = ctx->data + phdr->connection_offset; + ctx->bytes_remaining = phdr->connection_length; + break; + case PARSERSTRING_NAME: + ctx->curr = ctx->data + phdr->name_offset; + ctx->bytes_remaining = phdr->name_length; + break; + default: + break; + } + +Away: + return; +} + +void +parser_done(struct parser_context *ctx) +{ + if (!ctx) + return; + controlvm_payload_bytes_buffered -= ctx->param_bytes; + kfree(ctx); +} + +/** Return length of string not counting trailing spaces. */ +static int +string_length_no_trail(char *s, int len) +{ + int i = len - 1; + + while (i >= 0) { + if (!isspace(s[i])) + return i + 1; + i--; + } + return 0; +} + +/** Grab the next name and value out of the parameter buffer. + * The entire parameter buffer looks like this: + * <name>=<value>\0 + * <name>=<value>\0 + * ... + * \0 + * If successful, the next <name> value is returned within the supplied + * <nam> buffer (the value is always upper-cased), and the corresponding + * <value> is returned within a kmalloc()ed buffer, whose pointer is + * provided as the return value of this function. + * (The total number of bytes allocated is strlen(<value>)+1.) + * + * NULL is returned to indicate failure, which can occur for several reasons: + * - all <name>=<value> pairs have already been processed + * - bad parameter + * - parameter buffer ends prematurely (couldn't find an '=' or '\0' within + * the confines of the parameter buffer) + * - the <nam> buffer is not large enough to hold the <name> of the next + * parameter + */ +void * +parser_param_get(struct parser_context *ctx, char *nam, int namesize) +{ + u8 *pscan, *pnam = nam; + unsigned long nscan; + int value_length = -1, orig_value_length = -1; + void *value = NULL; + int i; + int closing_quote = 0; + + if (!ctx) + return NULL; + pscan = ctx->curr; + nscan = ctx->bytes_remaining; + if (nscan == 0) + return NULL; + if (*pscan == '\0') + /* This is the normal return point after you have processed + * all of the <name>=<value> pairs in a syntactically-valid + * parameter buffer. + */ + return NULL; + + /* skip whitespace */ + while (isspace(*pscan)) { + pscan++; + nscan--; + if (nscan == 0) + return NULL; + } + + while (*pscan != ':') { + if (namesize <= 0) + return NULL; + *pnam = toupper(*pscan); + pnam++; + namesize--; + pscan++; + nscan--; + if (nscan == 0) + return NULL; + } + if (namesize <= 0) + return NULL; + *pnam = '\0'; + nam[string_length_no_trail(nam, strlen(nam))] = '\0'; + + /* point to char immediately after ":" in "<name>:<value>" */ + pscan++; + nscan--; + /* skip whitespace */ + while (isspace(*pscan)) { + pscan++; + nscan--; + if (nscan == 0) + return NULL; + } + if (nscan == 0) + return NULL; + if (*pscan == '\'' || *pscan == '"') { + closing_quote = *pscan; + pscan++; + nscan--; + if (nscan == 0) + return NULL; + } + + /* look for a separator character, terminator character, or + * end of data + */ + for (i = 0, value_length = -1; i < nscan; i++) { + if (closing_quote) { + if (pscan[i] == '\0') + return NULL; + if (pscan[i] == closing_quote) { + value_length = i; + break; + } + } else + if (pscan[i] == ',' || pscan[i] == ';' + || pscan[i] == '\0') { + value_length = i; + break; + } + } + if (value_length < 0) { + if (closing_quote) + return NULL; + value_length = nscan; + } + orig_value_length = value_length; + if (closing_quote == 0) + value_length = string_length_no_trail(pscan, orig_value_length); + value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY); + if (value == NULL) + return NULL; + memcpy(value, pscan, value_length); + ((u8 *) (value))[value_length] = '\0'; + + pscan += orig_value_length; + nscan -= orig_value_length; + + /* skip past separator or closing quote */ + if (nscan > 0) { + if (*pscan != '\0') { + pscan++; + nscan--; + } + } + + if (closing_quote && (nscan > 0)) { + /* we still need to skip around the real separator if present */ + /* first, skip whitespace */ + while (isspace(*pscan)) { + pscan++; + nscan--; + if (nscan == 0) + break; + } + if (nscan > 0) { + if (*pscan == ',' || *pscan == ';') { + pscan++; + nscan--; + } else if (*pscan != '\0') { + kfree(value); + value = NULL; + return NULL; + } + } + } + ctx->curr = pscan; + ctx->bytes_remaining = nscan; + return value; +} + +void * +parser_string_get(struct parser_context *ctx) +{ + u8 *pscan; + unsigned long nscan; + int value_length = -1; + void *value = NULL; + int i; + + if (!ctx) + return NULL; + pscan = ctx->curr; + nscan = ctx->bytes_remaining; + if (nscan == 0) + return NULL; + if (!pscan) + return NULL; + for (i = 0, value_length = -1; i < nscan; i++) + if (pscan[i] == '\0') { + value_length = i; + break; + } + if (value_length < 0) /* '\0' was not included in the length */ + value_length = nscan; + value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY); + if (value == NULL) + return NULL; + if (value_length > 0) + memcpy(value, pscan, value_length); + ((u8 *) (value))[value_length] = '\0'; + return value; +} + + static ssize_t toolaction_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2274,13 +2679,13 @@ visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel) cdev_init(&file_cdev, &visorchipset_fops); file_cdev.owner = THIS_MODULE; if (MAJOR(major_dev) == 0) { - rc = alloc_chrdev_region(&major_dev, 0, 1, MYDRVNAME); + rc = alloc_chrdev_region(&major_dev, 0, 1, "visorchipset"); /* dynamic major device number registration required */ if (rc < 0) return rc; } else { /* static major device number registration required */ - rc = register_chrdev_region(major_dev, 1, MYDRVNAME); + rc = register_chrdev_region(major_dev, 1, "visorchipset"); if (rc < 0) return rc; } |