|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH v2 1/7] lib/uklibparam: Introduce the library parameter
Hi Sharan, this patch looks good.
-- Felipe
Reviewed-by: Felipe Huici <felipe.huici@xxxxxxxxx>
On 15.08.19, 13:49, "Minios-devel on behalf of Felipe Huici"
<minios-devel-bounces@xxxxxxxxxxxxxxxxxxxx on behalf of Felipe.Huici@xxxxxxxxx>
wrote:
Hi Sharan,
Thanks for fixing the extensive list of comments from Florian. There are
still cases where providing maliciously-formatted strings (e.g.,
test.testarr2=\"'''''''''''''''''''\"\"\"wef238@#*(@#\") causes unexpected
behavior, but I'm satisfied that the code can handle most common typos/errors
-- we're not trying to be robust to intentionally malicious behavior.
I have one more minor comment inline.
-- Felipe
On 13.08.19, 14:37, "Minios-devel on behalf of Sharan Santhanam"
<minios-devel-bounces@xxxxxxxxxxxxxxxxxxxx on behalf of
Sharan.Santhanam@xxxxxxxxx> wrote:
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.
Change since v1:
Signed-off-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
---
MAINTAINERS.md | 5 +
lib/Config.uk | 1 +
lib/Makefile.uk | 1 +
lib/ukboot/Makefile.uk | 1 +
lib/ukboot/exportsyms.uk | 1 +
lib/ukboot/include/uk/version.h | 6 +
lib/ukboot/version.c | 11 +
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 | 531 +++++++++++++++++++++++++++
12 files changed, 985 insertions(+)
create mode 100644 lib/ukboot/include/uk/version.h
create mode 100644 lib/ukboot/version.c
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 f61d3b1e..e7b26c8e 100644
--- a/lib/Config.uk
+++ b/lib/Config.uk
@@ -49,3 +49,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 b7ad6287..6f817afc 100644
--- a/lib/Makefile.uk
+++ b/lib/Makefile.uk
@@ -26,3 +26,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/ukboot/Makefile.uk b/lib/ukboot/Makefile.uk
index 55f205df..ea052019 100644
--- a/lib/ukboot/Makefile.uk
+++ b/lib/ukboot/Makefile.uk
@@ -4,6 +4,7 @@ CINCLUDES-$(CONFIG_LIBUKBOOT) +=
-I$(LIBUKBOOT_BASE)/include
CXXINCLUDES-$(CONFIG_LIBUKBOOT) += -I$(LIBUKBOOT_BASE)/include
LIBUKBOOT_SRCS-y += $(LIBUKBOOT_BASE)/boot.c
+LIBUKBOOT_SRCS-y += $(LIBUKBOOT_BASE)/version.c
# The main() is in the separate library to fool the LTO. Which is
# trying to resolve the main() function call to whatever is available
diff --git a/lib/ukboot/exportsyms.uk b/lib/ukboot/exportsyms.uk
index 3edc6c6a..4bce9274 100644
--- a/lib/ukboot/exportsyms.uk
+++ b/lib/ukboot/exportsyms.uk
@@ -1,3 +1,4 @@
ukplat_entry_argp
ukplat_entry
main
+uk_version
diff --git a/lib/ukboot/include/uk/version.h
b/lib/ukboot/include/uk/version.h
new file mode 100644
index 00000000..a1b31c3d
--- /dev/null
+++ b/lib/ukboot/include/uk/version.h
@@ -0,0 +1,6 @@
+#ifndef _UK_VERSION_H
+#define _UK_VERSION_H
+
+void uk_version(void);
+
+#endif /* _UK_VERSION_H */
diff --git a/lib/ukboot/version.c b/lib/ukboot/version.c
new file mode 100644
index 00000000..559e842d
--- /dev/null
+++ b/lib/ukboot/version.c
@@ -0,0 +1,11 @@
+#include <uk/version.h>
+#include <uk/essentials.h>
+#include <stdio.h>
+
+void uk_version(void)
+{
+ printf("Unikraft "
+ STRINGIFY(UK_CODENAME) " "
+ STRINGIFY(UK_FULLVERSION) "\n");
+}
+
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..d11acd3f
--- /dev/null
+++ b/lib/uklibparam/param.c
@@ -0,0 +1,531 @@
+/* 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)
+
+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 = args[i];
+ pargs->param_len = 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 = args[i];
+ pargs->param_len = 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 = 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;
+ 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));
Just to make this a bit more user friendly, it would be good to print out
the actual argument, not just the index. This would be particularly useful when
providing a large list of args.
+ 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
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |