[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Minios-devel] [UNIKRAFT PATCH 1/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>
---
 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 | 402 +++++++++++++++++++++++++++++
 lib/uklibparam/param.c               | 480 +++++++++++++++++++++++++++++++++++
 7 files changed, 898 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/lib/Config.uk b/lib/Config.uk
index 7d86f76..a630d15 100644
--- a/lib/Config.uk
+++ b/lib/Config.uk
@@ -45,3 +45,4 @@ source "lib/ukswrand/Config.uk"
 source "lib/ukbus/Config.uk"
 source "lib/uksglist/Config.uk"
 source "lib/uknetdev/Config.uk"
+source "lib/uklibparam/Config.uk"
diff --git a/lib/Makefile.uk b/lib/Makefile.uk
index d66c7ee..c1a4544 100644
--- a/lib/Makefile.uk
+++ b/lib/Makefile.uk
@@ -22,3 +22,4 @@ $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukmpi))
 $(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/uklibparam))
diff --git a/lib/uklibparam/Config.uk b/lib/uklibparam/Config.uk
new file mode 100644
index 0000000..18bb43d
--- /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 0000000..d354152
--- /dev/null
+++ b/lib/uklibparam/Makefile.uk
@@ -0,0 +1,7 @@
+$(eval $(call addlib_s,libuklibparam,$(CONFIG_LIBUKLIBPARAM)))
+
+ASINCLUDES-$(CONFIG_LIBUKLIBPARAM)     += -I$(LIBUKLIBPARAM_BASE)/include
+CINCLUDES-$(CONFIG_LIBUKLIBPARAM)      += -I$(LIBUKLIBPARAM_BASE)/include
+CXXINCLUDES-$(CONFIG_LIBUKLIBPARAM)    += -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 0000000..94b6ca7
--- /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 0000000..0855d2d
--- /dev/null
+++ b/lib/uklibparam/include/uk/libparam.h
@@ -0,0 +1,402 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
+ *
+ *
+ * Copyright (c) 2018, 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/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)
+
+#ifndef __ASSEMBLY__
+/**
+ * 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)
+
+/**
+ * Get the parameter type.
+ * @param size
+ *     The size of the parameter.
+ * @param sign
+ *     The sign of the data type.
+ * @param scopy
+ *     Flag to indicate shallow copy.
+ *     1 - shallow copy.
+ *     0 - data copy.
+ */
+#define PARAM_TYPE(size, sign, scopy)                          \
+               (                                               \
+                       ((((__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(sizeof(__s8), 1, 0)
+#define _LIB_PARAM_char                _LIB_PARAM___s8
+#define _LIB_PARAM___u8                PARAM_TYPE(sizeof(__u8), 0, 0)
+#define _LIB_PARAM___s16       PARAM_TYPE(sizeof(__s16), 1, 0)
+#define _LIB_PARAM___u16       PARAM_TYPE(sizeof(__u16), 0, 0)
+#define _LIB_PARAM___s32       PARAM_TYPE(sizeof(__s32), 1, 0)
+#define _LIB_PARAM_int         _LIB_PARAM___s32
+#define _LIB_PARAM___u32       PARAM_TYPE(sizeof(__u32), 0, 0)
+#define _LIB_PARAM___s64       PARAM_TYPE(sizeof(__s64), 1, 0)
+#define _LIB_PARAM___u64       PARAM_TYPE(sizeof(__u64), 0, 0)
+
+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)                        \
+                              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 suffix
+ *     The suffix
+ */
+#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 _LIB_PARAM_SECTION_ADD(                            \
+                               _LIB_PARAM_SECTION_NAME(section,        \
+                                                       LIB_NAME_SUFFIX),\
+                                                       char)           \
+               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            \
+                       }
+
+/**
+ * Create a constructor to initialize the parameters in the library.
+ */
+#define UK_LIB_CONSTRUCTOR_CREATE(libname)                             \
+       static void __constructor_prio(101)                             \
+       _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)
+
+
+/**
+ * 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                                                    \
+       _LIB_PARAM_SECTION_ADD(                                         \
+                               _LIB_PARAM_SECTION_NAME(                \
+                                               UK_LIBPARAM_PREFIX,     \
+                                               PARAM_NAME_SUFFIX),     \
+                                               char                    \
+                             )                                         \
+       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) &param_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)                                \
+
+
+#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 0000000..eb263be
--- /dev/null
+++ b/lib/uklibparam/param.c
@@ -0,0 +1,480 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, 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/print.h>
+#include <uk/assert.h>
+#include <uk/libparam.h>
+
+#define LIB_ARG_SEP     "--"
+
+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 */
+       __u8 lib_len;
+       /* length of the parameter */
+       __u8 param_len;
+       /* length of the value */
+       __u8 value_len;
+};
+
+static UK_LIST_HEAD(uk_libsections);
+
+/**
+ * Local functions
+ */
+static int kernel_arg_range_fetch(int argc, char **argv);
+static void uk_version(void);
+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_version(void)
+{
+       printf("Unikraft "
+               STRINGIFY(UK_CODENAME) " "
+               STRINGIFY(UK_FULLVERSION) "\n");
+}
+
+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_idx;
+       int len;
+       int cnt = 0;
+
+       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_err("Iteration :%d %s\n", i, args[i]);
+               len = strlen(args[i]);
+               /* Identify if there equal character is available */
+               equals_idx = strchr(args[i], '=');
+               cnt++;
+
+               if (equals_idx && (len > 1) &&
+                   (equals_idx - args[i]) == (len - 1)) {
+                       /* [libname_prefix].[parameter]= value */
+                       if (!pargs->param) {
+                               pargs->param = args[i];
+                               pargs->param_len = len - 1;
+                       } else {
+                               uk_pr_err("Invalid char (=) in value: %s\n",
+                                         args[i]);
+                               rc = -EINVAL;
+                               goto error_exit;
+                       }
+               } else if (equals_idx && len == 1)
+                       /* Contains only equals */
+                       continue;
+               else if (equals_idx &&
+                        (equals_idx - args[i]) < (len - 1)) {
+                       if (!pargs->param) {
+                               uk_pr_debug("Expecting Entire Argument%s\n",
+                                           args[i]);
+                               /* [libname_prefix].[parameter]=value */
+                               pargs->param = args[i];
+                               pargs->param_len = equals_idx - args[i];
+
+                               pargs->value = equals_idx + 1;
+                               pargs->value_len = len - (pargs->param_len + 1);
+                       } else {
+                               /* [libname_prefix].[parameter] =value */
+                               pargs->value =  equals_idx + 1;
+                               pargs->value_len = len - 1;
+                       }
+               } else if (!equals_idx) {
+                       /* [libname_prefix].[parameter] = value */
+                       if (!pargs->param) {
+                               uk_pr_debug("Expecting Parameter Only %s\n",
+                                               args[i]);
+                               pargs->param = args[i];
+                               pargs->param_len = len;
+                       } else {
+                               uk_pr_debug("Expecting Value Only %s\n",
+                                           args[i]);
+                               pargs->value = args[i];
+                               pargs->value_len = len;
+                       }
+               } else {
+                       uk_pr_err("Failed to parse the argument:%s\n", args[i]);
+                       rc = -EINVAL;
+                       goto error_exit;
+               }
+       }
+
+       uk_pr_err("pargs->param: %p, pargs->value %p\n", pargs->param,
+                       pargs->value);
+       if (pargs->param_len != 0 && pargs->value_len == 0) {
+               uk_pr_err("No value provided for arg: %s\n", pargs->param);
+               rc = -EINVAL;
+               goto error_exit;
+       }
+
+error_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 = NULL;
+       int rc = -EINVAL;
+       struct uk_lib_section *iter;
+
+       UK_ASSERT(section);
+       pargs->lib_len = 0;
+       libparam = memchr(pargs->param, '.', pargs->param_len);
+       if (!libparam) {
+               uk_pr_err("Failed to identify the library\n");
+               rc = -EINVAL;
+               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);
+               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 rc;
+}
+
+static int kernel_parse_arg(struct param_args *pargs,
+                           struct uk_lib_section *section,
+                           struct uk_param **param)
+{
+       int rc = -EINVAL;
+       int i = 0;
+       struct uk_param *iter = NULL;
+       int len = 0;
+
+       UK_ASSERT(section && param);
+
+       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("%s -- %p\n", &pargs->param[0], iter->name);
+               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 rc;
+}
+
+static int kernel_arg_set(void *addr, char *value, int size, int sign)
+{
+       switch (size) {
+       case 1:
+               if (sign)
+                       *((__s8 *)addr) = *value;
+               else
+                       *((__u8 *)addr) = (__u8) strtoul(value, NULL, 10);
+
+               break;
+       case 2:
+               if (sign)
+                       *((__s16 *)addr) = (__s16) strtol(value, NULL, 10);
+               else
+                       *((__u16 *)addr) = (__u16) strtoul(value, NULL, 10);
+               break;
+       case 4:
+               if (sign)
+                       *((__s32 *)addr) = (__s32) strtol(value, NULL, 10);
+               else
+                       *((__u32 *)addr) = (__u32) strtoul(value, NULL, 10);
+               break;
+       case 8:
+               if (sign)
+                       *((__s64 *)addr) = (__s64) strtoll(value, NULL, 10);
+               else
+                       *((__u64 *)addr) = (__u64) strtoull(value, NULL, 10);
+               break;
+       default:
+               uk_pr_err("Cannot understand type of size %d\n", size);
+               return -EINVAL;
+
+       }
+       return 0;
+}
+
+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;
+
+       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.
+ */
+static int kernel_value_sanitize(struct param_args *pargs)
+{
+       int rc = 0;
+       char *ptr;
+       char *start_idx = NULL;
+       char *end_idx = NULL;
+       int  remove_space = 1;
+
+       UK_ASSERT(pargs && pargs->value);
+       ptr = pargs->value;
+       uk_pr_info("Cleaning value%s--%d\n", pargs->value, pargs->value_len);
+
+       while (*ptr != '\0') {
+               switch (*ptr) {
+               case '\0':
+                       goto exit;
+               case ' ':
+               case '\r':
+               case '\n':
+               case '\t':
+               case '\v':
+                       if (remove_space) {
+                               *ptr = '\0';
+                               pargs->value_len--;
+                       }
+                       ptr++;
+                       break;
+               case'\'':
+               case '"':
+                       if (start_idx) {
+                               remove_space = 1;
+                               end_idx = ptr;
+                       } else if (!(start_idx)) {
+                               remove_space = 0;
+                               start_idx = ptr;
+                       }
+                       ptr++;
+                       break;
+               default:
+                       remove_space = 0;
+                       ptr++;
+                       break;
+
+               }
+       }
+
+       uk_pr_debug("Value Start: %p Value End: %p\n", start_idx, end_idx);
+
+       if (start_idx && !end_idx) {
+               uk_pr_err("Malformed value string: %s\n", pargs->value);
+               rc = -EINVAL;
+       } else if (start_idx && end_idx &&
+                  ((pargs->value_len - 2) != (end_idx - (start_idx + 1)))) {
+               /* Removing the open and close quote from the value string */
+               uk_pr_err("Value string(%s) not quoted properly %d: %ld\n",
+                         pargs->value, pargs->value_len, ((end_idx -
+                         start_idx)));
+               rc = -EINVAL;
+       } else if (start_idx && end_idx) {
+               pargs->value = start_idx + 1;
+               uk_pr_debug("Removing quotes from value %s", pargs->value);
+               *start_idx = '\0';
+               *end_idx = '\0';
+               pargs->value_len = end_idx - pargs->value;
+               uk_pr_debug("to: %s\n", pargs->value);
+       }
+
+exit:
+       return rc;
+}
+
+int uk_libparam_parse(const char *progname, int argc, char **argv)
+{
+       int keindex = 0;
+       int rc = 0, cnt = 0, args_read;
+       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 kernel argument found\n");
+               return 0;
+       }
+
+       uk_pr_debug("kernel argument end %d\n", keindex);
+
+       while (cnt < keindex) {
+
+               /* Parsing the 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, &pargs, &args_read);
+               if (rc < 0) {
+                       uk_pr_err("Failed to fetch arg between index %d and 
%d\n",
+                                 cnt, (cnt + args_read));
+                       cnt += args_read;
+                       continue;
+               }
+               uk_pr_debug("kernel argument %s\n", pargs.param);
+               cnt += args_read;
+
+               /* Fetch library for the argument */
+               rc = kernel_lib_fetch(&pargs, &section);
+               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, &param);
+               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.7.4


_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.