|
[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 and Felipe,
I have a suggestion, please see inline.
On 8/15/19 1:48 PM, Felipe Huici 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 version changes in ukboot library should be in a patch with only
those changes and the current patch should only contain uklibparam changes.
>
> # 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
This should go in the ukboot version patch.
> 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 */
This should go in the ukboot version patch.
> 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");
> +}
> +
This should go in the ukboot version patch.
> 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 |