[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH v3 2/8] lib/uklibparam: Introduce the library parameter
This patch provides the header necessary to register a variable as an boot argument with Unikraft that may depend on user input. The patch provides an implementation for parsing scalar arguments. Signed-off-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> --- MAINTAINERS.md | 5 + lib/Config.uk | 1 + lib/Makefile.uk | 1 + lib/uklibparam/Config.uk | 5 + lib/uklibparam/Makefile.uk | 7 + lib/uklibparam/exportsyms.uk | 2 + lib/uklibparam/include/uk/libparam.h | 414 ++++++++++++++++++++ lib/uklibparam/param.c | 544 +++++++++++++++++++++++++++ 8 files changed, 979 insertions(+) create mode 100644 lib/uklibparam/Config.uk create mode 100644 lib/uklibparam/Makefile.uk create mode 100644 lib/uklibparam/exportsyms.uk create mode 100644 lib/uklibparam/include/uk/libparam.h create mode 100644 lib/uklibparam/param.c diff --git a/MAINTAINERS.md b/MAINTAINERS.md index e3eb898d..690ca7eb 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -126,6 +126,11 @@ Try to look for the most precise areas first. In case nothing fits use L: minios-devel@xxxxxxxxxxxxx F: lib/ukdebug/* + LIBUKLIBPARAM + M: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> + L: minios-devel@xxxxxxxxxxxxx + F: lib/uklibparam/* + UNIKRAFT GENERAL M: Simon Kuenzer <simon.kuenzer@xxxxxxxxx> M: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> diff --git a/lib/Config.uk b/lib/Config.uk index e97a9af3..204f5216 100644 --- a/lib/Config.uk +++ b/lib/Config.uk @@ -50,3 +50,4 @@ source "lib/ukbus/Config.uk" source "lib/uksglist/Config.uk" source "lib/uknetdev/Config.uk" source "lib/posix-libdl/Config.uk" +source "lib/uklibparam/Config.uk" diff --git a/lib/Makefile.uk b/lib/Makefile.uk index b41345de..ac1e38bc 100644 --- a/lib/Makefile.uk +++ b/lib/Makefile.uk @@ -27,3 +27,4 @@ $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukbus)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uksglist)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uknetdev)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/posix-libdl)) +$(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uklibparam)) diff --git a/lib/uklibparam/Config.uk b/lib/uklibparam/Config.uk new file mode 100644 index 00000000..18bb43d6 --- /dev/null +++ b/lib/uklibparam/Config.uk @@ -0,0 +1,5 @@ +config LIBUKLIBPARAM + bool "uk library parameter: Pass arguments to a unikraft library" + default n + select LIBUKDEBUG + select LIBNOLIBC if !HAVE_LIBC diff --git a/lib/uklibparam/Makefile.uk b/lib/uklibparam/Makefile.uk new file mode 100644 index 00000000..3d450b86 --- /dev/null +++ b/lib/uklibparam/Makefile.uk @@ -0,0 +1,7 @@ +$(eval $(call addlib_s,libuklibparam,$(CONFIG_LIBUKLIBPARAM))) + +ASINCLUDES-y += -I$(LIBUKLIBPARAM_BASE)/include +CINCLUDES-y += -I$(LIBUKLIBPARAM_BASE)/include +CXXINCLUDES-y += -I$(LIBUKLIBPARAM_BASE)/include + +LIBUKLIBPARAM_SRCS-y += $(LIBUKLIBPARAM_BASE)/param.c diff --git a/lib/uklibparam/exportsyms.uk b/lib/uklibparam/exportsyms.uk new file mode 100644 index 00000000..94b6ca77 --- /dev/null +++ b/lib/uklibparam/exportsyms.uk @@ -0,0 +1,2 @@ +uk_libparam_parse +_uk_libparam_lib_add diff --git a/lib/uklibparam/include/uk/libparam.h b/lib/uklibparam/include/uk/libparam.h new file mode 100644 index 00000000..454cc0d6 --- /dev/null +++ b/lib/uklibparam/include/uk/libparam.h @@ -0,0 +1,414 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> + * + * Copyright (c) 2019, NEC Europe Ltd., NEC Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +#ifndef __UK_LIBPARAM_H +#define __UK_LIBPARAM_H + +#include <uk/config.h> +#ifndef __ASSEMBLY__ +#include <uk/ctors.h> +#include <uk/arch/types.h> +#include <uk/essentials.h> +#include <uk/list.h> +#include <uk/print.h> + +#ifdef __cplusplus +extern C { +#endif /* __cplusplus */ +#endif /* !__ASSEMBLY__ */ + +/** + * Variable name prefix/suffix + */ +#define UK_LIBPARAM_SECTION uk_lib_arg +/** + * Library: section suffix for the name and the + * parameter. + */ +#define LIB_PARAM_SUFFIX __lib_param +#define LIB_NAME_SUFFIX __lib_str +/** + * Library variable names for the name and the + * parameter. + */ +#define LIB_PARAMVAR_PREFIX _lib_param_ +#define LIB_NAMEVAR_PREFIX _lib_name_ +/** + * Parameter within a library: section suffix for the name and the + * parameter. + */ +#define PARAM_SECTION_SUFFIX __param_arg +#define PARAM_NAME_SUFFIX __param_str +/** + * Parameter within a library: variable name prefix for the name and the + * parameter. + */ +#define PARAM_PARAMVAR_PREFIX _param_param_ +#define PARAM_NAMEVAR_PREFIX _param_name_ + +#define __STRINGCONCAT(x, y) x ## y + +/** + * Create a section name. + * @param libname + * The library name + * @param section + * The section suffix for the library + */ +#define _LIB_PARAM_SECTION_NAME(libname, section_name) \ + __STRINGCONCAT(libname, section_name) + +/** + * Macros to denote the start / stop of a section. + */ +#define _SECTION_START(name) __STRINGCONCAT(__start_, name) +#define _SECTION_STOP(name) __STRINGCONCAT(__stop_, name) + +/** + * Make sure there is a dummy implementation for the UK_PARAM family of + * functions. + */ +#ifndef CONFIG_LIBUKLIBPARAM +/** + * Declare a library param. + * @param name + * The name of the library param. + * @param type + * The type of the param. + */ +#define UK_LIB_PARAM(name, type) + +#else /* !CONFIG_LIBUKLIBPARAM */ +/** + * Each parameter is bit-mapped as follows: + * --------------------------------------- + * | sign | copy | size of the parameter | + * --------------------------------------- + * 7 6 5 0 + */ +/** + * Sign bit: Shift & Mask + */ +#define PARAM_SIGN_SHIFT (7) +#define PARAM_SIGN_MASK (0x1) +/** + * Shallow copy: Shift & Mask + */ +#define PARAM_SCOPY_SHIFT (6) +#define PARAM_SCOPY_MASK (0x1) +/** + * Size of the param: Shift & Mask + */ +#define PARAM_SIZE_SHIFT (0x0) +#define PARAM_SIZE_MASK (0x3F) + +#ifndef __ASSEMBLY__ +/** + * Get the parameter type. + * @param sign + * The sign of the data type. + * @param scopy + * Flag to indicate shallow copy. + * 1 - shallow copy. + * 0 - data copy. + * @param size + * The size of the parameter. + */ +#define PARAM_TYPE(sign, scopy, size) \ + ( \ + ((((__u8) (sign & PARAM_SIGN_MASK)) << \ + PARAM_SIGN_SHIFT) | \ + (((__u8) (scopy & PARAM_SCOPY_MASK)) << \ + PARAM_SCOPY_SHIFT) | \ + (((__u8) (size & PARAM_SIZE_MASK)) << \ + PARAM_SIZE_SHIFT)) \ + ) + +/** + * Support data types as parameters + */ +#define _LIB_PARAM___s8 PARAM_TYPE(1, 0, sizeof(__s8)) +#define _LIB_PARAM_char _LIB_PARAM___s8 +#define _LIB_PARAM___u8 PARAM_TYPE(0, 0, sizeof(__u8)) +#define _LIB_PARAM___s16 PARAM_TYPE(1, 0, sizeof(__s16)) +#define _LIB_PARAM___u16 PARAM_TYPE(0, 0, sizeof(__u16)) +#define _LIB_PARAM___s32 PARAM_TYPE(1, 0, sizeof(__s32)) +#define _LIB_PARAM_int _LIB_PARAM___s32 +#define _LIB_PARAM___u32 PARAM_TYPE(0, 0, sizeof(__u32)) +#define _LIB_PARAM___s64 PARAM_TYPE(1, 0, sizeof(__s64)) +#define _LIB_PARAM___u64 PARAM_TYPE(0, 0, sizeof(__u64)) + +struct uk_param { + /* The name of the param */ + const char *name; + /* Type information for the param */ + const __u8 param_type; + /* Type information for the variable size param */ + const __u8 param_size; + /* Define a reference to location of the parameter */ + __uptr addr; +}; + +struct uk_lib_section { + /* Library name */ + const char *lib_name; + /* Section header of the uk_param args */ + struct uk_param *sec_addr_start; + /* Length of the section */ + __u32 len; + /* Next section entry */ + struct uk_list_head next; +}; + +/** + * Parse through the kernel parameter + * @param progname + * The application name + * @param argc + * The number of arguments + * @param argv + * Reference to the command line arguments + * @return + * On success, return the number of argument parsed. + * On Failure, return the error code. + */ +int uk_libparam_parse(const char *progname, int argc, char **argv); + +/** + * Register the library containing kernel parameter. + * + * @param lib_sec + * A reference to the uk_lib_section. + */ +void _uk_libparam_lib_add(struct uk_lib_section *lib_sec); + +/** + * Add a variable to a specific section. + * @param section_name + * The name of the section. + * @param align_type + * The alignment requirements for the variable definitions. + */ +#define _LIB_PARAM_SECTION_ADD(section_name, align_type) \ + __attribute__ ((used, \ + section( \ + __STRINGIFY(section_name)), \ + aligned(sizeof(align_type)) \ + )) +/** + * Create a constructor name. + * @param libname + * The library name. + * @param suffix + * The suffix appended to the library name. + */ +#define _LIB_UK_CONSTRUCT_NAME(libname, suffix) \ + __STRINGCONCAT(libname, suffix) + +/** + * Create a variable name + * @param prefix + * The prefix to the variable name. + * @param name + * The name of the variable + */ +#define _LIB_VARNAME_SET(prefix, name) \ + __STRINGCONCAT(prefix, name) + +/** + * Import the section header. + * @param libname + * The library name. + * @param section_suffix + * The suffix string for the section name + */ +#define UK_LIB_IMPORT_SECTION_PARAMS(libname, section_suffix) \ + extern char *_SECTION_START( \ + _LIB_PARAM_SECTION_NAME(libname, \ + section_suffix)); \ + extern char *_SECTION_STOP( \ + _LIB_PARAM_SECTION_NAME(libname, \ + section_suffix)) \ + +/** + * Create a library name variable and uk_lib_section for each library. + * @param libname + * The library name. + */ +#define UK_LIB_SECTION_CREATE(section, libname) \ + static const char \ + _LIB_VARNAME_SET(LIB_NAMEVAR_PREFIX, libname)[] = \ + __STRINGIFY(libname); \ + static _LIB_PARAM_SECTION_ADD( \ + _LIB_PARAM_SECTION_NAME(section, \ + LIB_PARAM_SUFFIX), \ + void *) \ + struct uk_lib_section \ + _LIB_VARNAME_SET(LIB_PARAMVAR_PREFIX, libname) = \ + { .lib_name = __NULL, \ + .sec_addr_start = __NULL, .len = 0 \ + } + +#define UK_LIB_CTOR_PRIO 1 + +#define UK_LIB_CONSTRUCTOR_SETUP(prio, name) \ + __UK_CTOR_FUNC(prio, name) + +/** + * Create a constructor to initialize the parameters in the library. + */ +#define UK_LIB_CONSTRUCTOR_CREATE(libname) \ + static void _LIB_UK_CONSTRUCT_NAME(libname, process_arg)(void) \ + { \ + int len = (__uptr) &_SECTION_STOP( \ + _LIB_PARAM_SECTION_NAME( \ + libname, PARAM_SECTION_SUFFIX) \ + ) - \ + (__uptr) &_SECTION_START( \ + _LIB_PARAM_SECTION_NAME( \ + libname, PARAM_SECTION_SUFFIX) \ + ); \ + if (len > 0) { \ + _LIB_VARNAME_SET(LIB_PARAMVAR_PREFIX, libname). \ + sec_addr_start = \ + (struct uk_param *) \ + ALIGN_UP((__uptr) \ + &_SECTION_START( \ + _LIB_PARAM_SECTION_NAME(\ + libname, \ + PARAM_SECTION_SUFFIX)), \ + sizeof(void *)); \ + _LIB_VARNAME_SET(LIB_PARAMVAR_PREFIX, libname). \ + len = len; \ + _LIB_VARNAME_SET(LIB_PARAMVAR_PREFIX, libname). \ + lib_name = \ + &_LIB_VARNAME_SET( \ + LIB_NAMEVAR_PREFIX, \ + libname)[0]; \ + _uk_libparam_lib_add(&_LIB_VARNAME_SET( \ + LIB_PARAMVAR_PREFIX, \ + libname) \ + ); \ + } \ + } \ + +#define UK_LIB_CONSTRUCTOR_INIT(libname) \ + UK_LIB_IMPORT_SECTION_PARAMS(libname, \ + PARAM_SECTION_SUFFIX); \ + UK_LIB_SECTION_CREATE(UK_LIBPARAM_SECTION, libname); \ + UK_LIB_CONSTRUCTOR_CREATE(libname) \ + UK_LIB_CONSTRUCTOR_SETUP(UK_LIB_CTOR_PRIO, \ + _LIB_UK_CONSTRUCT_NAME(libname, process_arg)) + + +/** + * Create a constructor to fill in the parameter. + */ +#ifdef UK_LIBPARAM_PREFIX + UK_LIB_CONSTRUCTOR_INIT(UK_LIBPARAM_PREFIX); +#endif /* UK_LIBPARAM_PREFIX */ + +/** + * Create the fully qualified name of a parameter. + * + * @param libname + * The name of the library + * @param name + * The name of the parameter + */ +#define _LIB_PARAM_STRING(libname, name) \ + libname.name + +/** + * Initialize the parameter string in a variable. The name of the + * parameter is stored in a separate linker section. + * + * @param name + * The name of the variable + * @param value + * The string representation of the parameter. + */ +#define _LIB_PARAM_NAME_SET(name, value) \ + static const \ + char _LIB_VARNAME_SET(PARAM_NAMEVAR_PREFIX, name)[] = \ + __STRINGIFY(value) + + +/** + * Initialize the parameter structure. + * + * @param param_name + * The name of the parameter + * @param type + * The type of the parameter + * @param cnt + * The number of the elements of that type. + */ +#define _LIB_UK_PARAM_SET(param_name, type, cnt) \ + static const \ + _LIB_PARAM_SECTION_ADD( \ + _LIB_PARAM_SECTION_NAME( \ + UK_LIBPARAM_PREFIX, \ + PARAM_SECTION_SUFFIX), \ + void * \ + ) \ + struct uk_param _LIB_VARNAME_SET(PARAM_SECTION_SUFFIX, \ + param_name) = { \ + .name = _LIB_VARNAME_SET(PARAM_NAMEVAR_PREFIX, \ + param_name), \ + .param_type = _LIB_PARAM_##type, \ + .param_size = cnt, \ + .addr = (__uptr) ¶m_name, \ + } + +/** + * Declare a library param. + * @param name + * The name of the library param. + * @param type + * The type of the param. + */ +#define UK_LIB_PARAM(name, type) \ + _LIB_PARAM_NAME_SET(name, _LIB_PARAM_STRING(UK_LIBPARAM_PREFIX, \ + name)); \ + _LIB_UK_PARAM_SET(name, type, 1) +#endif /* !__ASSEMBLY__ */ +#endif /* CONFIG_LIBUKLIBPARAM */ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* !__ASSEMBLY */ + +#endif /* __UK_LIBPARAM_H */ diff --git a/lib/uklibparam/param.c b/lib/uklibparam/param.c new file mode 100644 index 00000000..666820dd --- /dev/null +++ b/lib/uklibparam/param.c @@ -0,0 +1,544 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> + * + * Copyright (c) 2019, NEC Europe Ltd., NEC Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <uk/list.h> +#include <uk/arch/limits.h> +#include <uk/print.h> +#include <uk/assert.h> +#include <uk/libparam.h> +#include <uk/version.h> + +#define LIB_ARG_SEP "--" +#define NUMBER_SET(fn, type, value, addr, max, min, errcode, result_type, fmt)\ + do { \ + errno = 0; \ + result_type result = (result_type)fn(value, NULL, 10); \ + unsigned long long maxvalue = \ + (sizeof(type) == sizeof(maxvalue)) ? \ + (result_type)-1 : \ + (1ULL << ((sizeof(type) << 3))) - 1; \ + uk_pr_debug("max value: 0x%llx\n", maxvalue); \ + if (errno != 0) \ + errcode = -errno; \ + else if (result >= maxvalue) { \ + errcode = 1; \ + *((type *)addr) = (type)(result & maxvalue); \ + } else { \ + errcode = 0; \ + *((type *)addr) = (type)(result & maxvalue); \ + } \ + uk_pr_debug("Converting value %s to %"fmt" %"fmt"\n", \ + value, *(type *)addr, result); \ + } while (0) + +#define PARGS_PARAM_SET(pargs, parameter, len) \ + do { \ + if ((pargs)->param_len) \ + uk_pr_warn("Found no value. Parameter %s skipped\n",\ + (pargs)->param); \ + (pargs)->param = (parameter); \ + (pargs)->param_len = (len); \ + } while (0) + +struct param_args { + /* Reference to the start of the library */ + char *lib; + /* Reference to the start of the parameter */ + char *param; + /* Reference to the start of the value */ + char *value; + /* length of the library name */ + __u32 lib_len; + /* length of the parameter */ + __u32 param_len; + /* length of the value */ + __u32 value_len; +}; + +static UK_LIST_HEAD(uk_libsections); + +/** + * Local functions + */ +static int kernel_arg_range_fetch(int argc, char **argv); +static void uk_usage(const char *progname); +static int kernel_arg_fetch(char **args, int nr_args, + struct param_args *pargs, int *rewind); +static int kernel_lib_fetch(struct param_args *pargs, + struct uk_lib_section **section); +static int kernel_parse_arg(struct param_args *pargs, + struct uk_lib_section *section, + struct uk_param **param); +static int kernel_arg_set(void *addr, char *value, int size, int sign); +static int kernel_args_set(struct param_args *pargs, + struct uk_param *param); +static int kernel_value_sanitize(struct param_args *pargs); + +void _uk_libparam_lib_add(struct uk_lib_section *lib_sec) +{ + uk_pr_info("libname: %s, %d\n", lib_sec->lib_name, lib_sec->len); + uk_list_add_tail(&lib_sec->next, &uk_libsections); +} + +static void uk_usage(const char *progname) +{ + printf("Usage: %s\n", progname); + printf(" [[UNIKRAFT KERNEL ARGUMENT]].. -- [[APPLICATION ARGUMENT]]..\n\n"); + printf("Unikraft library arguments:\n"); + printf("The library arguments are represented as [LIBPARAM_PREFIX].[PARAMNAME]\n\n"); + printf(" -h, --help display this help and exit\n"); + printf(" -V, --version display Unikraft version and exit\n"); +} + +static int kernel_arg_range_fetch(int argc, char **argv) +{ + int i = 0; + + while (i < argc) { + /* Separate the kernel param from the application parameters */ + if (strcmp(LIB_ARG_SEP, argv[i]) == 0) + return i; + i++; + } + + return -1; +} + +static int kernel_arg_fetch(char **args, int nr_args, + struct param_args *pargs, int *rewind) +{ + int i = 0; + int rc = 0; + char *equals_ptr = NULL, *dupl_ptr = NULL; + int len, cnt = 0, equals = -1; + + UK_ASSERT(rewind && pargs); + + pargs->param = NULL; + pargs->value = NULL; + pargs->param_len = 0; + pargs->value_len = 0; + + for (i = 0; (!pargs->value_len || + !pargs->param_len) && i < nr_args; i++) { + uk_pr_debug("at index:%d user args %s\n", i, args[i]); + len = strlen(args[i]); + /* if the equals character is present */ + if (!equals_ptr) + equals_ptr = strchr(args[i], '='); + cnt++; + /* Check for multiple '=' */ + dupl_ptr = strrchr(args[i], '='); + if (equals_ptr && dupl_ptr && equals_ptr != dupl_ptr) { + uk_pr_err("Multiple '=' character found. Skipping argument %s\n", + args[i]); + rc = -EINVAL; + goto exit; + } else if (equals < 0) { + /* Searching for the parameters */ + if (equals_ptr && (len > 1) && + (equals_ptr - args[i]) == (len - 1)) { + /* [libname_prefix].[parameter]= value */ + uk_pr_debug("Expecting parameter with equals %s\n", + args[i]); + PARGS_PARAM_SET(pargs, args[i], len - 1); + equals = i; + } else if (equals_ptr && (len > 1) && + equals_ptr == args[i]) { + /* [libname_prefix].[parameter] =value */ + uk_pr_debug("Expecting equals followed by value %s\n", + args[i]); + pargs->value = equals_ptr + 1; + pargs->value_len = len - 1; + equals = i; + } else if (equals_ptr && len == 1) { + /* Contains only equals */ + equals = i; + continue; + } else if (equals_ptr) { + /* [libname_prefix].[parameter]=value */ + uk_pr_debug("Expecting entire argument %s\n", + args[i]); + PARGS_PARAM_SET(pargs, args[i], + equals_ptr - args[i]); + equals = i; + pargs->value = equals_ptr + 1; + pargs->value_len = len - (pargs->param_len + 1); + } else if (!equals_ptr) { + /* [libname_prefix].[parameter] = value */ + uk_pr_debug("Expecting parameter alone%s\n", + args[i]); + PARGS_PARAM_SET(pargs, args[i], len); + pargs->param = args[i]; + pargs->param_len = len; + } else { + uk_pr_err("Failed to parse the argument %s\n", + args[i]); + rc = -EINVAL; + goto exit; + } + } else if (equals >= 0) { + uk_pr_debug("Expecting value only %s\n", + args[i]); + pargs->value = args[i]; + pargs->value_len = len; + } else { + /* Error case */ + uk_pr_err("Failed to parse the argument:%s\n", args[i]); + rc = -EINVAL; + goto exit; + + } + } + + uk_pr_debug("pargs->param: %p, pargs->value: %p\n", pargs->param, + pargs->value); + if (pargs->param_len != 0 && pargs->value_len == 0) { + uk_pr_err("Failed to completely parse the user argument\n"); + rc = -EINVAL; + goto exit; + } + +exit: + *rewind = cnt; + return rc; +} + +/** + * Kernel Parameter are passed in this format + * [libname_prefix].[parameter] + */ +static int kernel_lib_fetch(struct param_args *pargs, + struct uk_lib_section **section) +{ + char *libparam; + struct uk_lib_section *iter; + + UK_ASSERT(section && pargs); + pargs->lib_len = 0; + libparam = memchr(pargs->param, '.', pargs->param_len); + if (!libparam) { + uk_pr_err("Failed to identify the library\n"); + goto error_exit; + } + + uk_list_for_each_entry(iter, &uk_libsections, next) { + uk_pr_debug("Lib: %s, libname: %s %ld\n", iter->lib_name, + pargs->param, libparam - pargs->param); + /** + * Compare the length of the library names to avoid having + * library with a similar prefix wrongly matching. + */ + if ((strlen(iter->lib_name) == + (size_t) (libparam - pargs->param)) && + memcmp(pargs->param, iter->lib_name, + (libparam - pargs->param)) == 0) { + *section = iter; + pargs->lib_len = libparam - pargs->param; + return 0; + } + } + uk_pr_err("Failed to fetch the library\n"); + +error_exit: + *section = NULL; + pargs->lib_len = 0; + return -EINVAL; +} + +static int kernel_parse_arg(struct param_args *pargs, + struct uk_lib_section *section, + struct uk_param **param) +{ + int i = 0; + struct uk_param *iter; + int len = 0; + + UK_ASSERT(section && param && pargs); + + len = section->len / sizeof(struct uk_param); + iter = section->sec_addr_start; + uk_pr_debug("Section length %d section@%p, uk_param: %lu\n", len, iter, + sizeof(*iter)); + + for (i = 0; i < len; i++, iter++) { + UK_ASSERT(iter->name); + uk_pr_debug("Param name: %s at address: %p\n", iter->name, + iter); + /** + * Compare the length of the library names to avoid having + * library with a similar prefix wrongly matching. + */ + if ((strlen(iter->name) == pargs->param_len) && + memcmp(iter->name, pargs->param, pargs->param_len) == 0) { + *param = iter; + return 0; + } + } + + uk_pr_err("Failed to identify the parameter\n"); + *param = NULL; + return -EINVAL; +} + +static int kernel_arg_set(void *addr, char *value, int size, int sign) +{ + int error = 0; + + /** + * Check for the output address instead of UK_ASSERT because this is + * a user provided input. + */ + if (!addr) { + uk_pr_err("Invalid output buffer\n"); + goto error_exit; + } + + switch (size) { + case 1: + if (sign) { + *((__s8 *)addr) = *value; + if (strnlen(value, 2) > 1) + error = 1; + } else + NUMBER_SET(strtoul, __u8, value, addr, __U8_MAX, + __U8_MIN, error, __u32, __PRIu8); + break; + case 2: + if (sign) + NUMBER_SET(strtol, __s16, value, addr, __S16_MAX, + __S16_MIN, error, __u32, __PRIs16); + else + NUMBER_SET(strtoul, __u16, value, addr, __U16_MAX, + __U16_MIN, error, __u32, __PRIu16); + break; + case 4: + if (sign) + NUMBER_SET(strtol, __s32, value, addr, __S32_MAX, + __S32_MIN, error, __u32, __PRIs32); + else + NUMBER_SET(strtoul, __u32, value, addr, __U32_MAX, + __U32_MIN, error, __u32, __PRIu32); + break; + case 8: + if (sign) + NUMBER_SET(strtoll, __s64, value, addr, __S64_MAX, + __S64_MIN, error, __u64, __PRIs64); + else + NUMBER_SET(strtoull, __u64, value, addr, __U64_MAX, + __U64_MIN, error, __u64, __PRIu64); + break; + default: + uk_pr_err("Cannot understand type of size %d\n", size); + goto error_exit; + } + if (error < 0) + goto error_exit; + else if (error == 1) + uk_pr_warn("Overflow/Underflow detected in value %s\n", value); + return 0; + +error_exit: + uk_pr_err("Failed to convert value %s\n", value); + return -EINVAL; +} + +static int kernel_args_set(struct param_args *pargs, + struct uk_param *param) +{ + int rc = 0; + int sign = (param->param_type >> PARAM_SIGN_SHIFT) & PARAM_SIGN_MASK; + int scopy = (param->param_type >> PARAM_SCOPY_SHIFT) & PARAM_SCOPY_MASK; + int param_type = (param->param_type >> PARAM_SIZE_SHIFT) + & PARAM_SIZE_MASK; + uk_pr_debug("Parameter value %s, type: %d, sign: %d scopy: %d\n", + pargs->value, param_type, sign, scopy); + + if (scopy == 1) + /* Reference the pointer instead of copying the value */ + *((__uptr *)param->addr) = (__uptr) pargs->value; + else { + if (param->param_size == 1) { + rc = kernel_arg_set((void *)param->addr, + pargs->value, param_type, sign); + } else { + uk_pr_err("Error: Cannot find the parameter\n"); + rc = -EINVAL; + } + } + + return rc; +} + +/** + * The function removes parse for quotes around the value. + * TODO: We do not support nested '"'. + */ +static int kernel_value_sanitize(struct param_args *pargs) +{ + int rc = 0; + char *ptr; + char *start_idx = NULL; + char *end_idx = NULL; + int qcnt = 0; + + UK_ASSERT(pargs && pargs->value); + ptr = pargs->value; + uk_pr_debug("Sanitizing value %s (length %d)\n", pargs->value, + pargs->value_len); + + do { + switch (*ptr) { + case ' ': + case '\r': + case '\n': + case '\t': + case '\v': + ptr++; + break; + case'\'': + case '"': + if (start_idx) + end_idx = ptr; + else if (!start_idx) + start_idx = ptr + 1; + ptr++; + qcnt++; + break; + default: + if (!start_idx) + start_idx = ptr; + ptr++; + break; + } + } while (*ptr != '\0' && !(end_idx && start_idx)); + if (!end_idx) + end_idx = ptr; + + uk_pr_debug("Adjusting start to %p & end to %p #quotes: %d\n", + start_idx, end_idx, qcnt); + + if (qcnt == 1) { + uk_pr_err("Value %s not quoted properly\n", pargs->value); + rc = -EINVAL; + } else if (start_idx && end_idx) { + memset(pargs->value, '\0', start_idx - pargs->value); + memset(end_idx, '\0', + (pargs->value + pargs->value_len) - end_idx); + pargs->value = start_idx; + pargs->value_len = end_idx - start_idx; + } + uk_pr_debug("Sanitized value %s (length %d)\n", pargs->value, + pargs->value_len); + + return rc; +} + +int uk_libparam_parse(const char *progname, int argc, char **argv) +{ + int keindex = 0; + int rc = 0, cnt = 0, args_read, i; + struct param_args pargs = {0}; + struct uk_lib_section *section = NULL; + struct uk_param *param = NULL; + + keindex = kernel_arg_range_fetch(argc, argv); + if (keindex < 0) { + uk_pr_info("No library arguments found\n"); + return 0; + } + + uk_pr_debug("Library argument ends at %d\n", keindex); + + while (cnt < keindex) { + /* help and version */ + if (strcmp(argv[cnt], "-h") == 0 || + strcmp(argv[cnt], "--help") == 0) { + uk_usage(progname); + ukplat_halt(); + } else if (strcmp(argv[cnt], "-V") == 0 || + strcmp(argv[cnt], "--version") == 0) { + uk_version(); + ukplat_halt(); + } + + args_read = 0; + /* Fetch the argument from the input */ + rc = kernel_arg_fetch(&argv[cnt], (keindex - cnt), + &pargs, &args_read); + if (rc < 0) { + uk_pr_err("Failed to fetch arg between index %d and %d\n", + cnt, (cnt + args_read)); + uk_pr_err("Skipping Args:"); + for ( i = cnt; i < cnt + args_read; i++) + uk_pr_err(" %s", argv[i]); + uk_pr_err("\n"); + cnt += args_read; + continue; + } + uk_pr_debug("Processing argument %s\n", pargs.param); + cnt += args_read; + + /* Fetch library for the argument */ + rc = kernel_lib_fetch(&pargs, §ion); + if (rc < 0 || !section) { + uk_pr_err("Failed to identify the library\n"); + continue; + } + + /* Fetch the parameter for the argument */ + rc = kernel_parse_arg(&pargs, section, ¶m); + if (rc < 0 || !param) { + uk_pr_err("Failed to parse arg\n"); + continue; + } + + rc = kernel_value_sanitize(&pargs); + if (rc < 0) { + uk_pr_err("Failed to sanitize %s param\n", pargs.param); + continue; + } + + rc = kernel_args_set(&pargs, param); + uk_pr_info("Parsed %d args\n", cnt); + } + + /* Replacing the -- with progname */ + argv[keindex] = DECONST(char *, progname); + + return keindex + 1; +} -- 2.20.1 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |