[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) &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)
        +#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, &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.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

 


Rackspace

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