Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/sysinfo/sysinfo.c

    r137691a re1b6742  
    3737#include <print.h>
    3838#include <syscall/copy.h>
     39#include <synch/spinlock.h>
     40#include <arch/asm.h>
     41#include <errno.h>
     42
     43/** Maximal sysinfo path length */
     44#define SYSINFO_MAX_PATH  2048
    3945
    4046bool fb_exported = false;
    41 sysinfo_item_t *_root = NULL;
    42 
    43 static sysinfo_item_t *sysinfo_find_item(const char *name, sysinfo_item_t *subtree)
    44 {
    45         if (subtree == NULL)
    46                 return NULL;
    47        
    48         while (subtree != NULL) {
    49                 int i = 0;
    50                 char *a = (char *) name;
    51                 char *b = subtree->name;
    52                
    53                 while ((a[i] == b[i]) && (b[i]))
     47
     48/** Global sysinfo tree root item */
     49static sysinfo_item_t *global_root = NULL;
     50
     51/** Sysinfo SLAB cache */
     52static slab_cache_t *sysinfo_item_slab;
     53
     54/** Sysinfo spinlock */
     55SPINLOCK_STATIC_INITIALIZE_NAME(sysinfo_lock, "sysinfo_lock");
     56
     57/** Sysinfo item constructor
     58 *
     59 */
     60static int sysinfo_item_constructor(void *obj, int kmflag)
     61{
     62        sysinfo_item_t *item = (sysinfo_item_t *) obj;
     63       
     64        item->name = NULL;
     65        item->val_type = SYSINFO_VAL_UNDEFINED;
     66        item->subtree_type = SYSINFO_SUBTREE_NONE;
     67        item->subtree.table = NULL;
     68        item->next = NULL;
     69       
     70        return 0;
     71}
     72
     73/** Sysinfo item destructor
     74 *
     75 * Note that the return value is not perfectly correct
     76 * since more space might get actually freed thanks
     77 * to the disposal of item->name
     78 *
     79 */
     80static int sysinfo_item_destructor(void *obj)
     81{
     82        sysinfo_item_t *item = (sysinfo_item_t *) obj;
     83       
     84        if (item->name != NULL)
     85                free(item->name);
     86       
     87        return 0;
     88}
     89
     90/** Initialize sysinfo subsystem
     91 *
     92 * Create SLAB cache for sysinfo items.
     93 *
     94 */
     95void sysinfo_init(void)
     96{
     97        sysinfo_item_slab = slab_cache_create("sysinfo_item_slab",
     98            sizeof(sysinfo_item_t), 0, sysinfo_item_constructor,
     99            sysinfo_item_destructor, SLAB_CACHE_MAGDEFERRED);
     100}
     101
     102/** Recursively find an item in sysinfo tree
     103 *
     104 * Should be called with interrupts disabled
     105 * and sysinfo_lock held.
     106 *
     107 * @param name    Current sysinfo path suffix.
     108 * @param subtree Current sysinfo (sub)tree root item.
     109 * @param ret     If the return value is NULL, this argument
     110 *                can be either also NULL (i.e. no item was
     111 *                found and no data was generated) or the
     112 *                original pointer is used to store the value
     113 *                generated by a generated subtree function.
     114 * @param dry_run Do not actually get any generated
     115 *                binary data, just calculate the size.
     116 *
     117 * @return Found item or NULL if no item in the fixed tree
     118 *         was found (N.B. ret).
     119 *
     120 */
     121static sysinfo_item_t *sysinfo_find_item(const char *name,
     122    sysinfo_item_t *subtree, sysinfo_return_t **ret, bool dry_run)
     123{
     124        ASSERT(subtree != NULL);
     125        ASSERT(ret != NULL);
     126       
     127        sysinfo_item_t *cur = subtree;
     128       
     129        /* Walk all siblings */
     130        while (cur != NULL) {
     131                size_t i = 0;
     132               
     133                /* Compare name with path */
     134                while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
    54135                        i++;
    55136               
    56                 if ((!a[i]) && (!b[i]))  /* Last name in path matches */
    57                         return subtree;
    58                
    59                 if ((a[i] == '.') && (!b[i])) { /* Middle name in path matches */
    60                         if (subtree->subinfo_type == SYSINFO_SUBINFO_TABLE)
    61                                 return sysinfo_find_item(a + i + 1, subtree->subinfo.table);
     137                /* Check for perfect name and path match */
     138                if ((name[i] == 0) && (cur->name[i] == 0))
     139                        return cur;
     140               
     141                /* Partial match up to the delimiter */
     142                if ((name[i] == '.') && (cur->name[i] == 0)) {
     143                        /* Look into the subtree */
     144                        switch (cur->subtree_type) {
     145                        case SYSINFO_SUBTREE_TABLE:
     146                                /* Recursively find in subtree */
     147                                return sysinfo_find_item(name + i + 1,
     148                                    cur->subtree.table, ret, dry_run);
     149                        case SYSINFO_SUBTREE_FUNCTION:
     150                                /* Get generated data */
     151                                **ret = cur->subtree.get_data(name + i + 1, dry_run);
     152                                return NULL;
     153                        default:
     154                                /* Not found, no data generated */
     155                                *ret = NULL;
     156                                return NULL;
     157                        }
     158                }
     159               
     160                cur = cur->next;
     161        }
     162       
     163        /* Not found, no data generated */
     164        *ret = NULL;
     165        return NULL;
     166}
     167
     168/** Recursively create items in sysinfo tree
     169 *
     170 * Should be called with interrupts disabled
     171 * and sysinfo_lock held.
     172 *
     173 * @param name     Current sysinfo path suffix.
     174 * @param psubtree Pointer to an already existing (sub)tree root
     175 *                 item or where to store a new tree root item.
     176 *
     177 * @return Existing or newly allocated sysinfo item or NULL
     178 *         if the current tree configuration does not allow to
     179 *         create a new item.
     180 *
     181 */
     182static sysinfo_item_t *sysinfo_create_path(const char *name,
     183    sysinfo_item_t **psubtree)
     184{
     185        ASSERT(psubtree != NULL);
     186       
     187        if (*psubtree == NULL) {
     188                /* No parent */
     189               
     190                size_t i = 0;
     191               
     192                /* Find the first delimiter in name */
     193                while ((name[i] != 0) && (name[i] != '.'))
     194                        i++;
     195               
     196                *psubtree =
     197                    (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
     198                ASSERT(*psubtree);
     199               
     200                /* Fill in item name up to the delimiter */
     201                (*psubtree)->name = str_ndup(name, i);
     202                ASSERT((*psubtree)->name);
     203               
     204                /* Create subtree items */
     205                if (name[i] == '.') {
     206                        (*psubtree)->subtree_type = SYSINFO_SUBTREE_TABLE;
     207                        return sysinfo_create_path(name + i + 1,
     208                            &((*psubtree)->subtree.table));
     209                }
     210               
     211                /* No subtree needs to be created */
     212                return *psubtree;
     213        }
     214       
     215        sysinfo_item_t *cur = *psubtree;
     216       
     217        /* Walk all siblings */
     218        while (cur != NULL) {
     219                size_t i = 0;
     220               
     221                /* Compare name with path */
     222                while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
     223                        i++;
     224               
     225                /* Check for perfect name and path match
     226                 * -> item is already present.
     227                 */
     228                if ((name[i] == 0) && (cur->name[i] == 0))
     229                        return cur;
     230               
     231                /* Partial match up to the delimiter */
     232                if ((name[i] == '.') && (cur->name[i] == 0)) {
     233                        switch (cur->subtree_type) {
     234                        case SYSINFO_SUBTREE_NONE:
     235                                /* No subtree yet, create one */
     236                                cur->subtree_type = SYSINFO_SUBTREE_TABLE;
     237                                return sysinfo_create_path(name + i + 1,
     238                                    &(cur->subtree.table));
     239                        case SYSINFO_SUBTREE_TABLE:
     240                                /* Subtree already created, add new sibling */
     241                                return sysinfo_create_path(name + i + 1,
     242                                    &(cur->subtree.table));
     243                        default:
     244                                /* Subtree items handled by a function, this
     245                                 * cannot be overriden by a constant item.
     246                                 */
     247                                return NULL;
     248                        }
     249                }
     250               
     251                /* No match and no more siblings to check
     252                 * -> create a new sibling item.
     253                 */
     254                if (cur->next == NULL) {
     255                        /* Find the first delimiter in name */
     256                        i = 0;
     257                        while ((name[i] != 0) && (name[i] != '.'))
     258                                i++;
    62259                       
    63                         //if (subtree->subinfo_type == SYSINFO_SUBINFO_FUNCTION) /* Subinfo managed by subsystem */
    64                         //      return NULL;
     260                        sysinfo_item_t *item =
     261                            (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
     262                        ASSERT(item);
    65263                       
    66                         return NULL; /* No subinfo */
    67                 }
    68                 /* No matches try next */
    69                 subtree = subtree->next;
    70         }
    71         return NULL;
    72 }
    73 
    74 static sysinfo_item_t *sysinfo_create_path(const char *name, sysinfo_item_t **psubtree)
    75 {
    76         sysinfo_item_t *subtree;
    77         subtree = *psubtree;
    78        
    79         if (subtree == NULL) {
    80                 sysinfo_item_t *item = malloc(sizeof(sysinfo_item_t), 0);
    81                 int i = 0, j;
     264                        cur->next = item;
    82265                       
    83                 ASSERT(item);
    84                 *psubtree = item;
    85                 item->next = NULL;
    86                 item->val_type = SYSINFO_VAL_UNDEFINED;
    87                 item->subinfo.table = NULL;
    88 
    89                 while (name[i] && (name[i] != '.'))
    90                         i++;
     266                        /* Fill in item name up to the delimiter */
     267                        item->name = str_ndup(name, i);
     268                        ASSERT(item->name);
    91269                       
    92                 item->name = malloc(i, 0);
    93                 ASSERT(item->name);
    94 
    95                 for (j = 0; j < i; j++)
    96                         item->name[j] = name[j];
    97                 item->name[j] = 0;
    98                        
    99                 if (name[i]) { /* =='.' */
    100                         item->subinfo_type = SYSINFO_SUBINFO_TABLE;
    101                         return sysinfo_create_path(name + i + 1, &(item->subinfo.table));
    102                 }
    103                 item->subinfo_type = SYSINFO_SUBINFO_NONE;
    104                 return item;
    105         }
    106 
    107         while (subtree != NULL) {
    108                 int i = 0, j;
    109                 char *a = (char *) name;
    110                 char *b = subtree->name;
    111                
    112                 while ((a[i] == b[i]) && (b[i]))
    113                         i++;
    114                
    115                 if ((!a[i]) && (!b[i])) /* Last name in path matches */
    116                         return subtree;
    117                
    118                 if ((a[i] == '.') && (!b[i])) { /* Middle name in path matches */
    119                         if (subtree->subinfo_type == SYSINFO_SUBINFO_TABLE)
    120                                 return sysinfo_create_path(a + i + 1, &(subtree->subinfo.table));
    121                        
    122                         if (subtree->subinfo_type == SYSINFO_SUBINFO_NONE) {
    123                                 subtree->subinfo_type = SYSINFO_SUBINFO_TABLE;
    124                                 return sysinfo_create_path(a + i + 1,&(subtree->subinfo.table));
     270                        /* Create subtree items */
     271                        if (name[i] == '.') {
     272                                item->subtree_type = SYSINFO_SUBTREE_TABLE;
     273                                return sysinfo_create_path(name + i + 1,
     274                                    &(item->subtree.table));
    125275                        }
    126276                       
    127                         //if (subtree->subinfo_type == SYSINFO_SUBINFO_FUNCTION) /* Subinfo managed by subsystem */
    128                         //      return NULL;
    129                        
    130                         return NULL;
     277                        /* No subtree needs to be created */
     278                        return item;
    131279                }
    132                 /* No matches try next or create new*/
    133                 if (subtree->next == NULL) {
    134                         sysinfo_item_t *item = malloc(sizeof(sysinfo_item_t), 0);
    135                        
    136                         ASSERT(item);
    137                         subtree->next = item;
    138                         item->next = NULL;
    139                         item->val_type = SYSINFO_VAL_UNDEFINED;
    140                         item->subinfo.table = NULL;
    141 
    142                         i = 0;
    143                         while (name[i] && (name[i] != '.'))
    144                                 i++;
    145 
    146                         item->name = malloc(i, 0);
    147                         ASSERT(item->name);
    148                        
    149                         for (j = 0; j < i; j++)
    150                                 item->name[j] = name[j];
    151                        
    152                         item->name[j] = 0;
    153 
    154                         if(name[i]) { /* =='.' */
    155                                 item->subinfo_type = SYSINFO_SUBINFO_TABLE;
    156                                 return sysinfo_create_path(name + i + 1, &(item->subinfo.table));
    157                         }
    158                         item->subinfo_type = SYSINFO_SUBINFO_NONE;
    159                         return item;
    160                 } else
    161                         subtree = subtree->next;
    162         }
    163 
    164         panic("Not reached.");
     280               
     281                cur = cur->next;
     282        }
     283       
     284        /* Unreachable */
     285        ASSERT(false);
    165286        return NULL;
    166287}
    167288
    168 void sysinfo_set_item_val(const char *name, sysinfo_item_t **root, unative_t val)
    169 {
     289/** Set sysinfo item with a constant numeric value
     290 *
     291 * @param name Sysinfo path.
     292 * @param root Pointer to the root item or where to store
     293 *             a new root item (NULL for global sysinfo root).
     294 * @param val  Value to store in the item.
     295 *
     296 */
     297void sysinfo_set_item_val(const char *name, sysinfo_item_t **root,
     298    unative_t val)
     299{
     300        /* Protect sysinfo tree consistency */
     301        ipl_t ipl = interrupts_disable();
     302        spinlock_lock(&sysinfo_lock);
     303       
    170304        if (root == NULL)
    171                 root = &_root;
    172        
    173         /* If already created create only returns pointer
    174            If not, create it */
     305                root = &global_root;
     306       
    175307        sysinfo_item_t *item = sysinfo_create_path(name, root);
    176        
    177         if (item != NULL) { /* If in subsystem, unable to create or return so unable to set */
    178                 item->val.val = val;                   
     308        if (item != NULL) {
    179309                item->val_type = SYSINFO_VAL_VAL;
    180         }
    181 }
    182 
    183 void sysinfo_set_item_function(const char *name, sysinfo_item_t **root, sysinfo_val_fn_t fn)
    184 {
     310                item->val.val = val;
     311        }
     312       
     313        spinlock_unlock(&sysinfo_lock);
     314        interrupts_restore(ipl);
     315}
     316
     317/** Set sysinfo item with a constant binary data
     318 *
     319 * Note that sysinfo only stores the pointer to the
     320 * binary data and does not touch it in any way. The
     321 * data should be static and immortal.
     322 *
     323 * @param name Sysinfo path.
     324 * @param root Pointer to the root item or where to store
     325 *             a new root item (NULL for global sysinfo root).
     326 * @param data Binary data.
     327 * @param size Size of the binary data.
     328 *
     329 */
     330void sysinfo_set_item_data(const char *name, sysinfo_item_t **root,
     331    void *data, size_t size)
     332{
     333        /* Protect sysinfo tree consistency */
     334        ipl_t ipl = interrupts_disable();
     335        spinlock_lock(&sysinfo_lock);
     336       
    185337        if (root == NULL)
    186                 root = &_root;
    187        
    188         /* If already created create only returns pointer
    189            If not, create it */
     338                root = &global_root;
     339       
    190340        sysinfo_item_t *item = sysinfo_create_path(name, root);
    191        
    192         if (item != NULL) { /* If in subsystem, unable to create or return so  unable to set */
    193                 item->val.fn = fn;                   
    194                 item->val_type = SYSINFO_VAL_FUNCTION;
    195         }
    196 }
    197 
    198 
     341        if (item != NULL) {
     342                item->val_type = SYSINFO_VAL_DATA;
     343                item->val.data.data = data;
     344                item->val.data.size = size;
     345        }
     346       
     347        spinlock_unlock(&sysinfo_lock);
     348        interrupts_restore(ipl);
     349}
     350
     351/** Set sysinfo item with a generated numeric value
     352 *
     353 * @param name Sysinfo path.
     354 * @param root Pointer to the root item or where to store
     355 *             a new root item (NULL for global sysinfo root).
     356 * @param fn   Numeric value generator function.
     357 *
     358 */
     359void sysinfo_set_item_fn_val(const char *name, sysinfo_item_t **root,
     360    sysinfo_fn_val_t fn)
     361{
     362        /* Protect sysinfo tree consistency */
     363        ipl_t ipl = interrupts_disable();
     364        spinlock_lock(&sysinfo_lock);
     365       
     366        if (root == NULL)
     367                root = &global_root;
     368       
     369        sysinfo_item_t *item = sysinfo_create_path(name, root);
     370        if (item != NULL) {
     371                item->val_type = SYSINFO_VAL_FUNCTION_VAL;
     372                item->val.fn_val = fn;
     373        }
     374       
     375        spinlock_unlock(&sysinfo_lock);
     376        interrupts_restore(ipl);
     377}
     378
     379/** Set sysinfo item with a generated binary data
     380 *
     381 * Note that each time the generator function is called
     382 * it is supposed to return a new dynamically allocated
     383 * data. This data is then freed by sysinfo in the context
     384 * of the current sysinfo request.
     385 *
     386 * @param name Sysinfo path.
     387 * @param root Pointer to the root item or where to store
     388 *             a new root item (NULL for global sysinfo root).
     389 * @param fn   Binary data generator function.
     390 *
     391 */
     392void sysinfo_set_item_fn_data(const char *name, sysinfo_item_t **root,
     393    sysinfo_fn_data_t fn)
     394{
     395        /* Protect sysinfo tree consistency */
     396        ipl_t ipl = interrupts_disable();
     397        spinlock_lock(&sysinfo_lock);
     398       
     399        if (root == NULL)
     400                root = &global_root;
     401       
     402        sysinfo_item_t *item = sysinfo_create_path(name, root);
     403        if (item != NULL) {
     404                item->val_type = SYSINFO_VAL_FUNCTION_DATA;
     405                item->val.fn_data = fn;
     406        }
     407       
     408        spinlock_unlock(&sysinfo_lock);
     409        interrupts_restore(ipl);
     410}
     411
     412/** Set sysinfo item with an undefined value
     413 *
     414 * @param name Sysinfo path.
     415 * @param root Pointer to the root item or where to store
     416 *             a new root item (NULL for global sysinfo root).
     417 *
     418 */
    199419void sysinfo_set_item_undefined(const char *name, sysinfo_item_t **root)
    200420{
     421        /* Protect sysinfo tree consistency */
     422        ipl_t ipl = interrupts_disable();
     423        spinlock_lock(&sysinfo_lock);
     424       
    201425        if (root == NULL)
    202                 root = &_root;
    203        
    204         /* If already created create only returns pointer
    205            If not, create it */
     426                root = &global_root;
     427       
    206428        sysinfo_item_t *item = sysinfo_create_path(name, root);
    207        
    208429        if (item != NULL)
    209430                item->val_type = SYSINFO_VAL_UNDEFINED;
    210 }
    211 
    212 
    213 void sysinfo_dump(sysinfo_item_t **proot, int depth)
    214 {
    215         sysinfo_item_t *root;
    216         if (proot == NULL)
    217                 proot = &_root;
    218        
    219         root = *proot;
    220        
    221         while (root != NULL) {
    222                 int i;
    223                 unative_t val = 0;
    224                 const char *vtype = NULL;
    225                
    226                
    227                 for (i = 0; i < depth; i++)
    228                         printf("  ");
    229                
    230                 switch (root->val_type) {
     431       
     432        spinlock_unlock(&sysinfo_lock);
     433        interrupts_restore(ipl);
     434}
     435
     436/** Set sysinfo item with a generated subtree
     437 *
     438 * @param name Sysinfo path.
     439 * @param root Pointer to the root item or where to store
     440 *             a new root item (NULL for global sysinfo root).
     441 * @param fn   Subtree generator function.
     442 *
     443 */
     444void sysinfo_set_subtree_fn(const char *name, sysinfo_item_t **root,
     445    sysinfo_fn_subtree_t fn)
     446{
     447        /* Protect sysinfo tree consistency */
     448        ipl_t ipl = interrupts_disable();
     449        spinlock_lock(&sysinfo_lock);
     450       
     451        if (root == NULL)
     452                root = &global_root;
     453       
     454        sysinfo_item_t *item = sysinfo_create_path(name, root);
     455       
     456        /* Change the type of the subtree only if it is not already
     457           a fixed subtree */
     458        if ((item != NULL) && (item->subtree_type != SYSINFO_SUBTREE_TABLE)) {
     459                item->subtree_type = SYSINFO_SUBTREE_FUNCTION;
     460                item->subtree.get_data = fn;
     461        }
     462       
     463        spinlock_unlock(&sysinfo_lock);
     464        interrupts_restore(ipl);
     465}
     466
     467/** Sysinfo dump indentation helper routine
     468 *
     469 * @param depth Number of indentation characters to print.
     470 *
     471 */
     472static void sysinfo_indent(unsigned int depth)
     473{
     474        unsigned int i;
     475        for (i = 0; i < depth; i++)
     476                printf("  ");
     477}
     478
     479/** Dump the structure of sysinfo tree
     480 *
     481 * Should be called with interrupts disabled
     482 * and sysinfo_lock held. Because this routine
     483 * might take a reasonable long time to proceed,
     484 * having the spinlock held is not optimal, but
     485 * there is no better simple solution.
     486 *
     487 * @param root  Root item of the current (sub)tree.
     488 * @param depth Current depth in the sysinfo tree.
     489 *
     490 */
     491static void sysinfo_dump_internal(sysinfo_item_t *root, unsigned int depth)
     492{
     493        sysinfo_item_t *cur = root;
     494       
     495        /* Walk all siblings */
     496        while (cur != NULL) {
     497                sysinfo_indent(depth);
     498               
     499                unative_t val;
     500                size_t size;
     501               
     502                /* Display node value and type */
     503                switch (cur->val_type) {
    231504                case SYSINFO_VAL_UNDEFINED:
    232                         val = 0;
    233                         vtype = "UND";
     505                        printf("+ %s\n", cur->name);
    234506                        break;
    235507                case SYSINFO_VAL_VAL:
    236                         val = root->val.val;
    237                         vtype = "VAL";
    238                         break;
    239                 case SYSINFO_VAL_FUNCTION:
    240                         val = ((sysinfo_val_fn_t) (root->val.fn)) (root);
    241                         vtype = "FUN";
    242                         break;
     508                        printf("+ %s -> %" PRIun" (%#" PRIxn ")\n", cur->name,
     509                            cur->val.val, cur->val.val);
     510                        break;
     511                case SYSINFO_VAL_DATA:
     512                        printf("+ %s (%" PRIs" bytes)\n", cur->name,
     513                            cur->val.data.size);
     514                        break;
     515                case SYSINFO_VAL_FUNCTION_VAL:
     516                        val = cur->val.fn_val(cur);
     517                        printf("+ %s -> %" PRIun" (%#" PRIxn ") [generated]\n",
     518                            cur->name, val, val);
     519                        break;
     520                case SYSINFO_VAL_FUNCTION_DATA:
     521                        /* N.B.: No data was actually returned (only a dry run) */
     522                        (void) cur->val.fn_data(cur, &size, true);
     523                        printf("+ %s (%" PRIs" bytes) [generated]\n", cur->name,
     524                            size);
     525                        break;
     526                default:
     527                        printf("+ %s [unknown]\n", cur->name);
    243528                }
    244529               
    245                 printf("%s    %s val:%" PRIun "(%" PRIxn ") sub:%s\n", root->name, vtype, val,
    246                         val, (root->subinfo_type == SYSINFO_SUBINFO_NONE) ?
    247                         "NON" : ((root->subinfo_type == SYSINFO_SUBINFO_TABLE) ?
    248                         "TAB" : "FUN"));
    249                
    250                 if (root->subinfo_type == SYSINFO_SUBINFO_TABLE)
    251                         sysinfo_dump(&(root -> subinfo.table), depth + 1);
    252                
    253                 root = root->next;
    254         }
    255 }
    256 
    257 sysinfo_rettype_t sysinfo_get_val(const char *name, sysinfo_item_t **root)
    258 {
    259         // TODO: Implement Subsystem subinfo (by function implemented subinfo)
    260 
    261         sysinfo_rettype_t ret = {0, false};
    262 
     530                /* Recursivelly nest into the subtree */
     531                switch (cur->subtree_type) {
     532                case SYSINFO_SUBTREE_NONE:
     533                        break;
     534                case SYSINFO_SUBTREE_TABLE:
     535                        sysinfo_dump_internal(cur->subtree.table, depth + 1);
     536                        break;
     537                case SYSINFO_SUBTREE_FUNCTION:
     538                        sysinfo_indent(depth + 1);
     539                        printf("+ [generated subtree]\n");
     540                        break;
     541                default:
     542                        sysinfo_indent(depth + 1);
     543                        printf("+ [unknown subtree]\n");
     544                }
     545               
     546                cur = cur->next;
     547        }
     548}
     549
     550/** Dump the structure of sysinfo tree
     551 *
     552 * @param root  Root item of the sysinfo (sub)tree.
     553 *              If it is NULL then consider the global
     554 *              sysinfo tree.
     555 *
     556 */
     557void sysinfo_dump(sysinfo_item_t *root)
     558{
     559        /* Avoid other functions to mess with sysinfo
     560           while we are dumping it */
     561        ipl_t ipl = interrupts_disable();
     562        spinlock_lock(&sysinfo_lock);
     563       
    263564        if (root == NULL)
    264                 root = &_root;
    265        
    266         sysinfo_item_t *item = sysinfo_find_item(name, *root);
     565                sysinfo_dump_internal(global_root, 0);
     566        else
     567                sysinfo_dump_internal(root, 0);
     568       
     569        spinlock_unlock(&sysinfo_lock);
     570        interrupts_restore(ipl);
     571}
     572
     573/** Return sysinfo item value determined by name
     574 *
     575 * Should be called with interrupts disabled
     576 * and sysinfo_lock held.
     577 *
     578 * @param name    Sysinfo path.
     579 * @param root    Root item of the sysinfo (sub)tree.
     580 *                If it is NULL then consider the global
     581 *                sysinfo tree.
     582 * @param dry_run Do not actually get any generated
     583 *                binary data, just calculate the size.
     584 *
     585 * @return Item value (constant or generated).
     586 *
     587 */
     588static sysinfo_return_t sysinfo_get_item(const char *name,
     589    sysinfo_item_t **root, bool dry_run)
     590{
     591        if (root == NULL)
     592                root = &global_root;
     593       
     594        /* Try to find the item or generate data */
     595        sysinfo_return_t ret;
     596        sysinfo_return_t *ret_ptr = &ret;
     597        sysinfo_item_t *item = sysinfo_find_item(name, *root, &ret_ptr,
     598            dry_run);
    267599       
    268600        if (item != NULL) {
    269                 if (item->val_type == SYSINFO_VAL_UNDEFINED)
    270                         return ret;
     601                /* Item found in the fixed sysinfo tree */
     602               
     603                ret.tag = item->val_type;
     604                switch (item->val_type) {
     605                case SYSINFO_VAL_UNDEFINED:
     606                        break;
     607                case SYSINFO_VAL_VAL:
     608                        ret.val = item->val.val;
     609                        break;
     610                case SYSINFO_VAL_DATA:
     611                        ret.data = item->val.data;
     612                        break;
     613                case SYSINFO_VAL_FUNCTION_VAL:
     614                        ret.val = item->val.fn_val(item);
     615                        break;
     616                case SYSINFO_VAL_FUNCTION_DATA:
     617                        ret.data.data = item->val.fn_data(item, &ret.data.size,
     618                            dry_run);
     619                        break;
     620                }
     621        } else {
     622                /* No item in the fixed sysinfo tree */
     623                if (ret_ptr == NULL) {
     624                        /* Even no data was generated */
     625                        ret.tag = SYSINFO_VAL_UNDEFINED;
     626                }
     627        }
     628       
     629        return ret;
     630}
     631
     632/** Return sysinfo item determined by name from user space
     633 *
     634 * Should be called with interrupts disabled
     635 * and sysinfo_lock held. The path string passed from
     636 * the user space has to be properly null-terminated
     637 * (the last passed character must be null).
     638 *
     639 * @param ptr     Sysinfo path in the user address space.
     640 * @param size    Size of the path string.
     641 * @param dry_run Do not actually get any generated
     642 *                binary data, just calculate the size.
     643 *
     644 */
     645static sysinfo_return_t sysinfo_get_item_uspace(void *ptr, size_t size,
     646    bool dry_run)
     647{
     648        sysinfo_return_t ret;
     649        ret.tag = SYSINFO_VAL_UNDEFINED;
     650       
     651        if (size > SYSINFO_MAX_PATH)
     652                return ret;
     653       
     654        char *path = (char *) malloc(size + 1, 0);
     655        ASSERT(path);
     656       
     657        if ((copy_from_uspace(path, ptr, size + 1) == 0)
     658            && (path[size] == 0))
     659                ret = sysinfo_get_item(path, NULL, dry_run);
     660       
     661        free(path);
     662        return ret;
     663}
     664
     665/** Get the sysinfo value type (syscall)
     666 *
     667 * The path string passed from the user space has
     668 * to be properly null-terminated (the last passed
     669 * character must be null).
     670 *
     671 * @param path_ptr  Sysinfo path in the user address space.
     672 * @param path_size Size of the path string.
     673 *
     674 * @return Item value type.
     675 *
     676 */
     677unative_t sys_sysinfo_get_tag(void *path_ptr, size_t path_size)
     678{
     679        /* Avoid other functions to mess with sysinfo
     680           while we are reading it */
     681        ipl_t ipl = interrupts_disable();
     682        spinlock_lock(&sysinfo_lock);
     683       
     684        /* Get the item.
     685       
     686           N.B.: There is no need to free any potential generated
     687           binary data since we request a dry run */
     688        sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
     689       
     690        /* Map generated value types to constant types
     691           (user space does not care whether the
     692           value is constant or generated) */
     693        if (ret.tag == SYSINFO_VAL_FUNCTION_VAL)
     694                ret.tag = SYSINFO_VAL_VAL;
     695        else if (ret.tag == SYSINFO_VAL_FUNCTION_DATA)
     696                ret.tag = SYSINFO_VAL_DATA;
     697       
     698        spinlock_unlock(&sysinfo_lock);
     699        interrupts_restore(ipl);
     700       
     701        return (unative_t) ret.tag;
     702}
     703
     704/** Get the sysinfo numerical value (syscall)
     705 *
     706 * The path string passed from the user space has
     707 * to be properly null-terminated (the last passed
     708 * character must be null).
     709 *
     710 * @param path_ptr  Sysinfo path in the user address space.
     711 * @param path_size Size of the path string.
     712 * @param value_ptr User space pointer where to store the
     713 *                  numberical value.
     714 *
     715 * @return Error code (EOK in case of no error).
     716 *
     717 */
     718unative_t sys_sysinfo_get_value(void *path_ptr, size_t path_size,
     719    void *value_ptr)
     720{
     721        /* Avoid other functions to mess with sysinfo
     722           while we are reading it */
     723        ipl_t ipl = interrupts_disable();
     724        spinlock_lock(&sysinfo_lock);
     725       
     726        /* Get the item.
     727       
     728           N.B.: There is no need to free any potential generated
     729           binary data since we request a dry run */
     730        sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
     731        int rc;
     732       
     733        /* Only constant or generated numerical value is returned */
     734        if ((ret.tag == SYSINFO_VAL_VAL) || (ret.tag == SYSINFO_VAL_FUNCTION_VAL))
     735                rc = copy_to_uspace(value_ptr, &ret.val, sizeof(ret.val));
     736        else
     737                rc = EINVAL;
     738       
     739        spinlock_unlock(&sysinfo_lock);
     740        interrupts_restore(ipl);
     741       
     742        return (unative_t) rc;
     743}
     744
     745/** Get the sysinfo binary data size (syscall)
     746 *
     747 * The path string passed from the user space has
     748 * to be properly null-terminated (the last passed
     749 * character must be null).
     750 *
     751 * @param path_ptr  Sysinfo path in the user address space.
     752 * @param path_size Size of the path string.
     753 * @param size_ptr  User space pointer where to store the
     754 *                  binary data size.
     755 *
     756 * @return Error code (EOK in case of no error).
     757 *
     758 */
     759unative_t sys_sysinfo_get_data_size(void *path_ptr, size_t path_size,
     760    void *size_ptr)
     761{
     762        /* Avoid other functions to mess with sysinfo
     763           while we are reading it */
     764        ipl_t ipl = interrupts_disable();
     765        spinlock_lock(&sysinfo_lock);
     766       
     767        /* Get the item.
     768       
     769           N.B.: There is no need to free any potential generated
     770           binary data since we request a dry run */
     771        sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
     772        int rc;
     773       
     774        /* Only the size of constant or generated binary data is considered */
     775        if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA))
     776                rc = copy_to_uspace(size_ptr, &ret.data.size,
     777                    sizeof(ret.data.size));
     778        else
     779                rc = EINVAL;
     780       
     781        spinlock_unlock(&sysinfo_lock);
     782        interrupts_restore(ipl);
     783       
     784        return (unative_t) rc;
     785}
     786
     787/** Get the sysinfo binary data (syscall)
     788 *
     789 * The path string passed from the user space has
     790 * to be properly null-terminated (the last passed
     791 * character must be null).
     792 *
     793 * The user space buffer must be sized exactly according
     794 * to the size of the binary data, otherwise the request
     795 * fails.
     796 *
     797 * @param path_ptr    Sysinfo path in the user address space.
     798 * @param path_size   Size of the path string.
     799 * @param buffer_ptr  User space pointer to the buffer where
     800 *                    to store the binary data.
     801 * @param buffer_size User space buffer size.
     802 *
     803 * @return Error code (EOK in case of no error).
     804 *
     805 */
     806unative_t sys_sysinfo_get_data(void *path_ptr, size_t path_size,
     807    void *buffer_ptr, size_t buffer_size)
     808{
     809        /* Avoid other functions to mess with sysinfo
     810           while we are reading it */
     811        ipl_t ipl = interrupts_disable();
     812        spinlock_lock(&sysinfo_lock);
     813       
     814        /* Get the item */
     815        sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, false);
     816        int rc;
     817       
     818        /* Only constant or generated binary data is considered */
     819        if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA)) {
     820                /* Check destination buffer size */
     821                if (ret.data.size == buffer_size)
     822                        rc = copy_to_uspace(buffer_ptr, ret.data.data,
     823                            ret.data.size);
    271824                else
    272                         ret.valid = true;
    273                
    274                 if (item->val_type == SYSINFO_VAL_VAL)
    275                         ret.val = item->val.val;
    276                 else
    277                         ret.val = ((sysinfo_val_fn_t) (item->val.fn)) (item);
    278         }
    279         return ret;
    280 }
    281 
    282 #define SYSINFO_MAX_LEN 1024
    283 
    284 unative_t sys_sysinfo_valid(unative_t ptr, unative_t len)
    285 {
    286         char *str;
    287         sysinfo_rettype_t ret = {0, 0};
    288 
    289         if (len > SYSINFO_MAX_LEN)
    290                 return ret.valid;
    291         str = malloc(len + 1, 0);
    292        
    293         ASSERT(str);
    294         if (!((copy_from_uspace(str, (void *) ptr, len + 1)) || (str[len])))
    295                 ret = sysinfo_get_val(str, NULL);
    296        
    297         free(str);
    298         return ret.valid;
    299 }
    300 
    301 unative_t sys_sysinfo_value(unative_t ptr, unative_t len)
    302 {
    303         char *str;
    304         sysinfo_rettype_t ret = {0, 0};
    305        
    306         if (len > SYSINFO_MAX_LEN)
    307                 return ret.val;
    308         str = malloc(len + 1, 0);
    309        
    310         ASSERT(str);
    311         if (!((copy_from_uspace(str, (void *) ptr, len + 1)) || (str[len])))
    312                 ret = sysinfo_get_val(str, NULL);
    313        
    314         free(str);
    315         return ret.val;
     825                        rc = ENOMEM;
     826        } else
     827                rc = EINVAL;
     828       
     829        /* N.B.: The generated binary data should be freed */
     830        if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
     831                free(ret.data.data);
     832       
     833        spinlock_unlock(&sysinfo_lock);
     834        interrupts_restore(ipl);
     835       
     836        return (unative_t) rc;
    316837}
    317838
Note: See TracChangeset for help on using the changeset viewer.