source: mainline/kernel/generic/src/sysinfo/sysinfo.c@ 853802e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 853802e was 63e27ef, checked in by Jiri Svoboda <jiri@…>, 9 years ago

ASSERT → assert

  • Property mode set to 100644
File size: 26.7 KB
RevLine 
[6326f5e6]1/*
[df4ed85]2 * Copyright (c) 2006 Jakub Vana
[196c253]3 * Copyright (c) 2012 Martin Decky
[6326f5e6]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[a71c158]30/** @addtogroup generic
[b45c443]31 * @{
32 */
33/** @file
34 */
35
[63e27ef]36#include <assert.h>
[2666daa]37#include <sysinfo/sysinfo.h>
38#include <mm/slab.h>
39#include <print.h>
[35a96cf]40#include <syscall/copy.h>
[6b6626d3]41#include <synch/mutex.h>
[a80687e5]42#include <arch/asm.h>
[d9fae235]43#include <errno.h>
[311bc25]44#include <macros.h>
[d9fae235]45
[80bfb601]46/** Maximal sysinfo path length */
[d9fae235]47#define SYSINFO_MAX_PATH 2048
[2666daa]48
[a71c158]49bool fb_exported = false;
[2666daa]50
[80bfb601]51/** Global sysinfo tree root item */
[d9fae235]52static sysinfo_item_t *global_root = NULL;
[80bfb601]53
54/** Sysinfo SLAB cache */
[d9fae235]55static slab_cache_t *sysinfo_item_slab;
56
[6b6626d3]57/** Sysinfo lock */
58static mutex_t sysinfo_lock;
[9dae191e]59
[80bfb601]60/** Sysinfo item constructor
61 *
62 */
[7a0359b]63NO_TRACE static int sysinfo_item_constructor(void *obj, unsigned int kmflag)
[d9fae235]64{
65 sysinfo_item_t *item = (sysinfo_item_t *) obj;
66
67 item->name = NULL;
68 item->val_type = SYSINFO_VAL_UNDEFINED;
69 item->subtree_type = SYSINFO_SUBTREE_NONE;
[b658c5d]70 item->subtree.table = NULL;
[d9fae235]71 item->next = NULL;
72
73 return 0;
74}
75
[80bfb601]76/** Sysinfo item destructor
77 *
78 * Note that the return value is not perfectly correct
79 * since more space might get actually freed thanks
80 * to the disposal of item->name
81 *
82 */
[7a0359b]83NO_TRACE static size_t sysinfo_item_destructor(void *obj)
[d9fae235]84{
85 sysinfo_item_t *item = (sysinfo_item_t *) obj;
86
87 if (item->name != NULL)
88 free(item->name);
89
90 return 0;
91}
92
[80bfb601]93/** Initialize sysinfo subsystem
94 *
95 * Create SLAB cache for sysinfo items.
96 *
97 */
[d9fae235]98void sysinfo_init(void)
99{
[f97f1e51]100 sysinfo_item_slab = slab_cache_create("sysinfo_item_t",
[d9fae235]101 sizeof(sysinfo_item_t), 0, sysinfo_item_constructor,
102 sysinfo_item_destructor, SLAB_CACHE_MAGDEFERRED);
[3d23553]103
[6b6626d3]104 mutex_initialize(&sysinfo_lock, MUTEX_ACTIVE);
[d9fae235]105}
106
[80bfb601]107/** Recursively find an item in sysinfo tree
[9dae191e]108 *
[c6218327]109 * Should be called with sysinfo_lock held.
[9dae191e]110 *
[80bfb601]111 * @param name Current sysinfo path suffix.
112 * @param subtree Current sysinfo (sub)tree root item.
113 * @param ret If the return value is NULL, this argument
[0030eef]114 * can be set either to NULL (i.e. no item was
[80bfb601]115 * found and no data was generated) or the
116 * original pointer is used to store the value
117 * generated by a generated subtree function.
[e1b6742]118 * @param dry_run Do not actually get any generated
119 * binary data, just calculate the size.
[80bfb601]120 *
121 * @return Found item or NULL if no item in the fixed tree
122 * was found (N.B. ret).
123 *
[9dae191e]124 */
[7a0359b]125NO_TRACE static sysinfo_item_t *sysinfo_find_item(const char *name,
[e1b6742]126 sysinfo_item_t *subtree, sysinfo_return_t **ret, bool dry_run)
[2666daa]127{
[63e27ef]128 assert(subtree != NULL);
[9dae191e]129
[d9fae235]130 sysinfo_item_t *cur = subtree;
[749122b]131
[80bfb601]132 /* Walk all siblings */
[d9fae235]133 while (cur != NULL) {
134 size_t i = 0;
[749122b]135
[d9fae235]136 /* Compare name with path */
137 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
[749122b]138 i++;
139
[d9fae235]140 /* Check for perfect name and path match */
141 if ((name[i] == 0) && (cur->name[i] == 0))
142 return cur;
[749122b]143
[d9fae235]144 /* Partial match up to the delimiter */
145 if ((name[i] == '.') && (cur->name[i] == 0)) {
146 /* Look into the subtree */
147 switch (cur->subtree_type) {
148 case SYSINFO_SUBTREE_TABLE:
149 /* Recursively find in subtree */
[9dae191e]150 return sysinfo_find_item(name + i + 1,
[e1b6742]151 cur->subtree.table, ret, dry_run);
[d9fae235]152 case SYSINFO_SUBTREE_FUNCTION:
[9dae191e]153 /* Get generated data */
[0030eef]154 if (ret != NULL)
155 **ret = cur->subtree.generator.fn(name + i + 1,
156 dry_run, cur->subtree.generator.data);
157
[9dae191e]158 return NULL;
[d9fae235]159 default:
[80bfb601]160 /* Not found, no data generated */
[0030eef]161 if (ret != NULL)
162 *ret = NULL;
163
[d9fae235]164 return NULL;
165 }
[2666daa]166 }
[d9fae235]167
168 cur = cur->next;
[2666daa]169 }
[d9fae235]170
[80bfb601]171 /* Not found, no data generated */
[0030eef]172 if (ret != NULL)
173 *ret = NULL;
174
[2666daa]175 return NULL;
176}
177
[9dae191e]178/** Recursively create items in sysinfo tree
179 *
[c6218327]180 * Should be called with sysinfo_lock held.
[9dae191e]181 *
[80bfb601]182 * @param name Current sysinfo path suffix.
183 * @param psubtree Pointer to an already existing (sub)tree root
184 * item or where to store a new tree root item.
185 *
186 * @return Existing or newly allocated sysinfo item or NULL
187 * if the current tree configuration does not allow to
188 * create a new item.
189 *
[9dae191e]190 */
[7a0359b]191NO_TRACE static sysinfo_item_t *sysinfo_create_path(const char *name,
[d9fae235]192 sysinfo_item_t **psubtree)
[2666daa]193{
[63e27ef]194 assert(psubtree != NULL);
[b658c5d]195
[d9fae235]196 if (*psubtree == NULL) {
197 /* No parent */
198
199 size_t i = 0;
200
201 /* Find the first delimiter in name */
202 while ((name[i] != 0) && (name[i] != '.'))
[7bb6b06]203 i++;
[d9fae235]204
205 *psubtree =
206 (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
[63e27ef]207 assert(*psubtree);
[d9fae235]208
209 /* Fill in item name up to the delimiter */
210 (*psubtree)->name = str_ndup(name, i);
[63e27ef]211 assert((*psubtree)->name);
[d9fae235]212
213 /* Create subtree items */
214 if (name[i] == '.') {
215 (*psubtree)->subtree_type = SYSINFO_SUBTREE_TABLE;
216 return sysinfo_create_path(name + i + 1,
217 &((*psubtree)->subtree.table));
[7bb6b06]218 }
[d9fae235]219
220 /* No subtree needs to be created */
221 return *psubtree;
[2666daa]222 }
[d9fae235]223
224 sysinfo_item_t *cur = *psubtree;
225
[80bfb601]226 /* Walk all siblings */
[d9fae235]227 while (cur != NULL) {
228 size_t i = 0;
[749122b]229
[d9fae235]230 /* Compare name with path */
231 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
[749122b]232 i++;
233
[d9fae235]234 /* Check for perfect name and path match
235 * -> item is already present.
236 */
237 if ((name[i] == 0) && (cur->name[i] == 0))
238 return cur;
[749122b]239
[d9fae235]240 /* Partial match up to the delimiter */
241 if ((name[i] == '.') && (cur->name[i] == 0)) {
242 switch (cur->subtree_type) {
243 case SYSINFO_SUBTREE_NONE:
244 /* No subtree yet, create one */
245 cur->subtree_type = SYSINFO_SUBTREE_TABLE;
246 return sysinfo_create_path(name + i + 1,
247 &(cur->subtree.table));
248 case SYSINFO_SUBTREE_TABLE:
249 /* Subtree already created, add new sibling */
250 return sysinfo_create_path(name + i + 1,
251 &(cur->subtree.table));
252 default:
253 /* Subtree items handled by a function, this
[80bfb601]254 * cannot be overriden by a constant item.
[d9fae235]255 */
256 return NULL;
[749122b]257 }
[2666daa]258 }
[d9fae235]259
260 /* No match and no more siblings to check
261 * -> create a new sibling item.
262 */
263 if (cur->next == NULL) {
264 /* Find the first delimiter in name */
[749122b]265 i = 0;
[d9fae235]266 while ((name[i] != 0) && (name[i] != '.'))
[749122b]267 i++;
268
[d9fae235]269 sysinfo_item_t *item =
270 (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
[63e27ef]271 assert(item);
[749122b]272
[d9fae235]273 cur->next = item;
274
275 /* Fill in item name up to the delimiter */
276 item->name = str_ndup(name, i);
[63e27ef]277 assert(item->name);
[d9fae235]278
279 /* Create subtree items */
280 if (name[i] == '.') {
281 item->subtree_type = SYSINFO_SUBTREE_TABLE;
282 return sysinfo_create_path(name + i + 1,
283 &(item->subtree.table));
[2666daa]284 }
[d9fae235]285
286 /* No subtree needs to be created */
[2666daa]287 return item;
[d9fae235]288 }
289
290 cur = cur->next;
[2666daa]291 }
[d9fae235]292
293 /* Unreachable */
[63e27ef]294 assert(false);
[2666daa]295 return NULL;
296}
297
[80bfb601]298/** Set sysinfo item with a constant numeric value
299 *
300 * @param name Sysinfo path.
301 * @param root Pointer to the root item or where to store
302 * a new root item (NULL for global sysinfo root).
303 * @param val Value to store in the item.
304 *
305 */
[d9fae235]306void sysinfo_set_item_val(const char *name, sysinfo_item_t **root,
[96b02eb9]307 sysarg_t val)
[2666daa]308{
[80bfb601]309 /* Protect sysinfo tree consistency */
[6b6626d3]310 mutex_lock(&sysinfo_lock);
[9dae191e]311
[749122b]312 if (root == NULL)
[d9fae235]313 root = &global_root;
[749122b]314
315 sysinfo_item_t *item = sysinfo_create_path(name, root);
[d9fae235]316 if (item != NULL) {
[749122b]317 item->val_type = SYSINFO_VAL_VAL;
[d9fae235]318 item->val.val = val;
[749122b]319 }
[9dae191e]320
[6b6626d3]321 mutex_unlock(&sysinfo_lock);
[2666daa]322}
323
[80bfb601]324/** Set sysinfo item with a constant binary data
325 *
326 * Note that sysinfo only stores the pointer to the
327 * binary data and does not touch it in any way. The
328 * data should be static and immortal.
329 *
330 * @param name Sysinfo path.
331 * @param root Pointer to the root item or where to store
332 * a new root item (NULL for global sysinfo root).
333 * @param data Binary data.
334 * @param size Size of the binary data.
335 *
336 */
[d9fae235]337void sysinfo_set_item_data(const char *name, sysinfo_item_t **root,
338 void *data, size_t size)
[2666daa]339{
[80bfb601]340 /* Protect sysinfo tree consistency */
[6b6626d3]341 mutex_lock(&sysinfo_lock);
[9dae191e]342
[749122b]343 if (root == NULL)
[d9fae235]344 root = &global_root;
[749122b]345
346 sysinfo_item_t *item = sysinfo_create_path(name, root);
[d9fae235]347 if (item != NULL) {
348 item->val_type = SYSINFO_VAL_DATA;
349 item->val.data.data = data;
350 item->val.data.size = size;
351 }
[9dae191e]352
[6b6626d3]353 mutex_unlock(&sysinfo_lock);
[d9fae235]354}
355
[80bfb601]356/** Set sysinfo item with a generated numeric value
357 *
358 * @param name Sysinfo path.
359 * @param root Pointer to the root item or where to store
360 * a new root item (NULL for global sysinfo root).
361 * @param fn Numeric value generator function.
[196c253]362 * @param data Private data.
[80bfb601]363 *
364 */
[196c253]365void sysinfo_set_item_gen_val(const char *name, sysinfo_item_t **root,
366 sysinfo_fn_val_t fn, void *data)
[d9fae235]367{
[80bfb601]368 /* Protect sysinfo tree consistency */
[6b6626d3]369 mutex_lock(&sysinfo_lock);
[9dae191e]370
[d9fae235]371 if (root == NULL)
372 root = &global_root;
[749122b]373
[d9fae235]374 sysinfo_item_t *item = sysinfo_create_path(name, root);
375 if (item != NULL) {
376 item->val_type = SYSINFO_VAL_FUNCTION_VAL;
[196c253]377 item->val.gen_val.fn = fn;
378 item->val.gen_val.data = data;
[749122b]379 }
[9dae191e]380
[6b6626d3]381 mutex_unlock(&sysinfo_lock);
[2666daa]382}
383
[80bfb601]384/** Set sysinfo item with a generated binary data
385 *
386 * Note that each time the generator function is called
387 * it is supposed to return a new dynamically allocated
388 * data. This data is then freed by sysinfo in the context
389 * of the current sysinfo request.
390 *
391 * @param name Sysinfo path.
392 * @param root Pointer to the root item or where to store
393 * a new root item (NULL for global sysinfo root).
394 * @param fn Binary data generator function.
[196c253]395 * @param data Private data.
[80bfb601]396 *
397 */
[196c253]398void sysinfo_set_item_gen_data(const char *name, sysinfo_item_t **root,
399 sysinfo_fn_data_t fn, void *data)
[d9fae235]400{
[80bfb601]401 /* Protect sysinfo tree consistency */
[6b6626d3]402 mutex_lock(&sysinfo_lock);
[9dae191e]403
[d9fae235]404 if (root == NULL)
405 root = &global_root;
406
407 sysinfo_item_t *item = sysinfo_create_path(name, root);
408 if (item != NULL) {
409 item->val_type = SYSINFO_VAL_FUNCTION_DATA;
[196c253]410 item->val.gen_data.fn = fn;
411 item->val.gen_data.data = data;
[d9fae235]412 }
[9dae191e]413
[6b6626d3]414 mutex_unlock(&sysinfo_lock);
[d9fae235]415}
[2666daa]416
[80bfb601]417/** Set sysinfo item with an undefined value
418 *
419 * @param name Sysinfo path.
420 * @param root Pointer to the root item or where to store
421 * a new root item (NULL for global sysinfo root).
422 *
423 */
[749122b]424void sysinfo_set_item_undefined(const char *name, sysinfo_item_t **root)
[2666daa]425{
[80bfb601]426 /* Protect sysinfo tree consistency */
[6b6626d3]427 mutex_lock(&sysinfo_lock);
[9dae191e]428
[749122b]429 if (root == NULL)
[d9fae235]430 root = &global_root;
[749122b]431
432 sysinfo_item_t *item = sysinfo_create_path(name, root);
433 if (item != NULL)
434 item->val_type = SYSINFO_VAL_UNDEFINED;
[9dae191e]435
[6b6626d3]436 mutex_unlock(&sysinfo_lock);
[2666daa]437}
438
[80bfb601]439/** Set sysinfo item with a generated subtree
440 *
441 * @param name Sysinfo path.
442 * @param root Pointer to the root item or where to store
443 * a new root item (NULL for global sysinfo root).
444 * @param fn Subtree generator function.
[5869ce0]445 * @param data Private data to be passed to the generator.
[80bfb601]446 *
447 */
[9dae191e]448void sysinfo_set_subtree_fn(const char *name, sysinfo_item_t **root,
[5869ce0]449 sysinfo_fn_subtree_t fn, void *data)
[9dae191e]450{
[80bfb601]451 /* Protect sysinfo tree consistency */
[6b6626d3]452 mutex_lock(&sysinfo_lock);
[9dae191e]453
454 if (root == NULL)
455 root = &global_root;
456
457 sysinfo_item_t *item = sysinfo_create_path(name, root);
[80bfb601]458
459 /* Change the type of the subtree only if it is not already
460 a fixed subtree */
[9dae191e]461 if ((item != NULL) && (item->subtree_type != SYSINFO_SUBTREE_TABLE)) {
462 item->subtree_type = SYSINFO_SUBTREE_FUNCTION;
[5869ce0]463 item->subtree.generator.fn = fn;
464 item->subtree.generator.data = data;
[9dae191e]465 }
466
[6b6626d3]467 mutex_unlock(&sysinfo_lock);
[9dae191e]468}
469
470/** Sysinfo dump indentation helper routine
[80bfb601]471 *
[efb8d15]472 * @param depth Number of spaces to print.
[9dae191e]473 *
474 */
[efb8d15]475NO_TRACE static void sysinfo_indent(size_t spaces)
[d9fae235]476{
[efb8d15]477 for (size_t i = 0; i < spaces; i++)
478 printf(" ");
[d9fae235]479}
[2666daa]480
[9dae191e]481/** Dump the structure of sysinfo tree
482 *
[c6218327]483 * Should be called with sysinfo_lock held.
[9dae191e]484 *
[efb8d15]485 * @param root Root item of the current (sub)tree.
486 * @param spaces Current indentation level.
[80bfb601]487 *
[9dae191e]488 */
[efb8d15]489NO_TRACE static void sysinfo_dump_internal(sysinfo_item_t *root, size_t spaces)
[2666daa]490{
[80bfb601]491 /* Walk all siblings */
[efb8d15]492 for (sysinfo_item_t *cur = root; cur; cur = cur->next) {
493 size_t length;
494
495 if (spaces == 0) {
496 printf("%s", cur->name);
497 length = str_length(cur->name);
498 } else {
499 sysinfo_indent(spaces);
500 printf(".%s", cur->name);
501 length = str_length(cur->name) + 1;
502 }
[2666daa]503
[96b02eb9]504 sysarg_t val;
[d9fae235]505 size_t size;
[2666daa]506
[80bfb601]507 /* Display node value and type */
[d9fae235]508 switch (cur->val_type) {
[f8ddd17]509 case SYSINFO_VAL_UNDEFINED:
[efb8d15]510 printf(" [undefined]\n");
[f8ddd17]511 break;
512 case SYSINFO_VAL_VAL:
[efb8d15]513 printf(" -> %" PRIun" (%#" PRIxn ")\n", cur->val.val,
514 cur->val.val);
[f8ddd17]515 break;
[d9fae235]516 case SYSINFO_VAL_DATA:
[efb8d15]517 printf(" (%zu bytes)\n", cur->val.data.size);
[f8ddd17]518 break;
[d9fae235]519 case SYSINFO_VAL_FUNCTION_VAL:
[196c253]520 val = cur->val.gen_val.fn(cur, cur->val.gen_val.data);
[efb8d15]521 printf(" -> %" PRIun" (%#" PRIxn ") [generated]\n", val,
522 val);
[d9fae235]523 break;
524 case SYSINFO_VAL_FUNCTION_DATA:
[70e2b2d]525 /* N.B.: No data was actually returned (only a dry run) */
[196c253]526 (void) cur->val.gen_data.fn(cur, &size, true,
527 cur->val.gen_data.data);
[efb8d15]528 printf(" (%zu bytes) [generated]\n", size);
[d9fae235]529 break;
530 default:
531 printf("+ %s [unknown]\n", cur->name);
[749122b]532 }
[2666daa]533
[80bfb601]534 /* Recursivelly nest into the subtree */
[d9fae235]535 switch (cur->subtree_type) {
536 case SYSINFO_SUBTREE_NONE:
537 break;
538 case SYSINFO_SUBTREE_TABLE:
[efb8d15]539 sysinfo_dump_internal(cur->subtree.table, spaces + length);
[d9fae235]540 break;
541 case SYSINFO_SUBTREE_FUNCTION:
[efb8d15]542 sysinfo_indent(spaces + length);
543 printf("<generated subtree>\n");
[d9fae235]544 break;
545 default:
[efb8d15]546 sysinfo_indent(spaces + length);
547 printf("<unknown subtree>\n");
[d9fae235]548 }
[749122b]549 }
[2666daa]550}
551
[80bfb601]552/** Dump the structure of sysinfo tree
553 *
554 * @param root Root item of the sysinfo (sub)tree.
555 * If it is NULL then consider the global
556 * sysinfo tree.
557 *
558 */
[9dae191e]559void sysinfo_dump(sysinfo_item_t *root)
560{
[80bfb601]561 /* Avoid other functions to mess with sysinfo
562 while we are dumping it */
[6b6626d3]563 mutex_lock(&sysinfo_lock);
[9dae191e]564
565 if (root == NULL)
566 sysinfo_dump_internal(global_root, 0);
567 else
568 sysinfo_dump_internal(root, 0);
569
[6b6626d3]570 mutex_unlock(&sysinfo_lock);
[9dae191e]571}
572
[80bfb601]573/** Return sysinfo item value determined by name
[9dae191e]574 *
[c6218327]575 * Should be called with sysinfo_lock held.
[9dae191e]576 *
[70e2b2d]577 * @param name Sysinfo path.
578 * @param root Root item of the sysinfo (sub)tree.
579 * If it is NULL then consider the global
580 * sysinfo tree.
581 * @param dry_run Do not actually get any generated
582 * binary data, just calculate the size.
[80bfb601]583 *
584 * @return Item value (constant or generated).
585 *
[9dae191e]586 */
[7a0359b]587NO_TRACE static sysinfo_return_t sysinfo_get_item(const char *name,
[70e2b2d]588 sysinfo_item_t **root, bool dry_run)
[2666daa]589{
[749122b]590 if (root == NULL)
[d9fae235]591 root = &global_root;
[749122b]592
[80bfb601]593 /* Try to find the item or generate data */
[d9fae235]594 sysinfo_return_t ret;
[9dae191e]595 sysinfo_return_t *ret_ptr = &ret;
[e1b6742]596 sysinfo_item_t *item = sysinfo_find_item(name, *root, &ret_ptr,
597 dry_run);
[749122b]598
599 if (item != NULL) {
[80bfb601]600 /* Item found in the fixed sysinfo tree */
601
[9dae191e]602 ret.tag = item->val_type;
[d9fae235]603 switch (item->val_type) {
604 case SYSINFO_VAL_UNDEFINED:
605 break;
606 case SYSINFO_VAL_VAL:
[749122b]607 ret.val = item->val.val;
[d9fae235]608 break;
609 case SYSINFO_VAL_DATA:
610 ret.data = item->val.data;
611 break;
612 case SYSINFO_VAL_FUNCTION_VAL:
[196c253]613 ret.val = item->val.gen_val.fn(item, item->val.gen_val.data);
[d9fae235]614 break;
615 case SYSINFO_VAL_FUNCTION_DATA:
[196c253]616 ret.data.data = item->val.gen_data.fn(item, &ret.data.size,
617 dry_run, item->val.gen_data.data);
[d9fae235]618 break;
619 }
[9dae191e]620 } else {
[80bfb601]621 /* No item in the fixed sysinfo tree */
622 if (ret_ptr == NULL) {
623 /* Even no data was generated */
[9dae191e]624 ret.tag = SYSINFO_VAL_UNDEFINED;
[80bfb601]625 }
[9dae191e]626 }
[d9fae235]627
628 return ret;
629}
630
[9dae191e]631/** Return sysinfo item determined by name from user space
632 *
[b4ad39f]633 * The path string passed from the user space has to be properly null-terminated
[80bfb601]634 * (the last passed character must be null).
635 *
[70e2b2d]636 * @param ptr Sysinfo path in the user address space.
637 * @param size Size of the path string.
638 * @param dry_run Do not actually get any generated
639 * binary data, just calculate the size.
[9dae191e]640 *
641 */
[7a0359b]642NO_TRACE static sysinfo_return_t sysinfo_get_item_uspace(void *ptr, size_t size,
[70e2b2d]643 bool dry_run)
[d9fae235]644{
645 sysinfo_return_t ret;
646 ret.tag = SYSINFO_VAL_UNDEFINED;
647
648 if (size > SYSINFO_MAX_PATH)
649 return ret;
650
651 char *path = (char *) malloc(size + 1, 0);
[63e27ef]652 assert(path);
[d9fae235]653
[3d23553]654 if ((copy_from_uspace(path, ptr, size + 1) == 0) &&
655 (path[size] == 0)) {
[b4ad39f]656 /*
657 * Prevent other functions from messing with sysinfo while we
658 * are reading it.
659 */
[6b6626d3]660 mutex_lock(&sysinfo_lock);
[70e2b2d]661 ret = sysinfo_get_item(path, NULL, dry_run);
[6b6626d3]662 mutex_unlock(&sysinfo_lock);
[b4ad39f]663 }
[3d23553]664
[9dae191e]665 free(path);
[2666daa]666 return ret;
667}
[35a96cf]668
[0030eef]669/** Return sysinfo keys determined by name
670 *
671 * Should be called with sysinfo_lock held.
672 *
673 * @param name Sysinfo path.
674 * @param root Root item of the sysinfo (sub)tree.
675 * If it is NULL then consider the global
676 * sysinfo tree.
677 * @param dry_run Do not actually get any generated
678 * binary data, just calculate the size.
679 *
680 * @return Item value (constant or generated).
681 *
682 */
683NO_TRACE static sysinfo_return_t sysinfo_get_keys(const char *name,
684 sysinfo_item_t **root, bool dry_run)
685{
686 if (root == NULL)
687 root = &global_root;
688
[76f382b]689 sysinfo_item_t *subtree = NULL;
690
691 if (name[0] != 0) {
692 /* Try to find the item */
693 sysinfo_item_t *item =
694 sysinfo_find_item(name, *root, NULL, dry_run);
695 if ((item != NULL) &&
696 (item->subtree_type == SYSINFO_SUBTREE_TABLE))
697 subtree = item->subtree.table;
698 } else
699 subtree = *root;
[0030eef]700
701 sysinfo_return_t ret;
702
[76f382b]703 if (subtree != NULL) {
[0030eef]704 /*
705 * Calculate the size of subkeys.
706 */
707 size_t size = 0;
[76f382b]708 for (sysinfo_item_t *cur = subtree; cur; cur = cur->next)
[0030eef]709 size += str_size(cur->name) + 1;
710
711 if (dry_run) {
[76f382b]712 ret.tag = SYSINFO_VAL_DATA;
[0030eef]713 ret.data.data = NULL;
714 ret.data.size = size;
715 } else {
716 /* Allocate buffer for subkeys */
717 char *names = (char *) malloc(size, FRAME_ATOMIC);
718 if (names == NULL)
719 return ret;
720
721 size_t pos = 0;
[76f382b]722 for (sysinfo_item_t *cur = subtree; cur; cur = cur->next) {
[0030eef]723 str_cpy(names + pos, size - pos, cur->name);
724 pos += str_size(cur->name) + 1;
725 }
726
727 /* Correct return value */
[76f382b]728 ret.tag = SYSINFO_VAL_DATA;
[0030eef]729 ret.data.data = (void *) names;
730 ret.data.size = size;
731 }
732 } else {
733 /* No item in the fixed sysinfo tree */
734 ret.tag = SYSINFO_VAL_UNDEFINED;
735 }
736
737 return ret;
738}
739
740/** Return sysinfo keys determined by name from user space
741 *
742 * The path string passed from the user space has to be properly
743 * null-terminated (the last passed character must be null).
744 *
745 * @param ptr Sysinfo path in the user address space.
746 * @param size Size of the path string.
747 * @param dry_run Do not actually get any generated
748 * binary data, just calculate the size.
749 *
750 */
751NO_TRACE static sysinfo_return_t sysinfo_get_keys_uspace(void *ptr, size_t size,
752 bool dry_run)
753{
754 sysinfo_return_t ret;
755 ret.tag = SYSINFO_VAL_UNDEFINED;
[2a08005]756 ret.data.data = NULL;
757 ret.data.size = 0;
[0030eef]758
759 if (size > SYSINFO_MAX_PATH)
760 return ret;
761
762 char *path = (char *) malloc(size + 1, 0);
[63e27ef]763 assert(path);
[0030eef]764
765 if ((copy_from_uspace(path, ptr, size + 1) == 0) &&
766 (path[size] == 0)) {
767 /*
768 * Prevent other functions from messing with sysinfo while we
769 * are reading it.
770 */
771 mutex_lock(&sysinfo_lock);
772 ret = sysinfo_get_keys(path, NULL, dry_run);
773 mutex_unlock(&sysinfo_lock);
774 }
775
776 free(path);
777 return ret;
778}
779
780/** Get the sysinfo keys size (syscall)
781 *
782 * The path string passed from the user space has
783 * to be properly null-terminated (the last passed
784 * character must be null).
785 *
786 * @param path_ptr Sysinfo path in the user address space.
787 * @param path_size Size of the path string.
788 * @param size_ptr User space pointer where to store the
789 * keys size.
790 *
791 * @return Error code (EOK in case of no error).
792 *
793 */
794sysarg_t sys_sysinfo_get_keys_size(void *path_ptr, size_t path_size,
795 void *size_ptr)
796{
797 int rc;
798
799 /*
800 * Get the keys.
801 *
802 * N.B.: There is no need to free any potential keys
803 * since we request a dry run.
804 */
805 sysinfo_return_t ret =
806 sysinfo_get_keys_uspace(path_ptr, path_size, true);
807
808 /* Check return data tag */
809 if (ret.tag == SYSINFO_VAL_DATA)
810 rc = copy_to_uspace(size_ptr, &ret.data.size,
811 sizeof(ret.data.size));
812 else
813 rc = EINVAL;
814
815 return (sysarg_t) rc;
816}
817
818/** Get the sysinfo keys (syscall)
819 *
820 * The path string passed from the user space has
821 * to be properly null-terminated (the last passed
822 * character must be null).
823 *
824 * If the user space buffer size does not equal
825 * the actual size of the returned data, the data
826 * is truncated.
827 *
828 * The actual size of data returned is stored to
829 * size_ptr.
830 *
831 * @param path_ptr Sysinfo path in the user address space.
832 * @param path_size Size of the path string.
833 * @param buffer_ptr User space pointer to the buffer where
834 * to store the binary data.
835 * @param buffer_size User space buffer size.
836 * @param size_ptr User space pointer where to store the
837 * binary data size.
838 *
839 * @return Error code (EOK in case of no error).
840 *
841 */
842sysarg_t sys_sysinfo_get_keys(void *path_ptr, size_t path_size,
843 void *buffer_ptr, size_t buffer_size, size_t *size_ptr)
844{
845 int rc;
846
847 /* Get the keys */
848 sysinfo_return_t ret = sysinfo_get_keys_uspace(path_ptr, path_size,
849 false);
850
851 /* Check return data tag */
852 if (ret.tag == SYSINFO_VAL_DATA) {
853 size_t size = min(ret.data.size, buffer_size);
854 rc = copy_to_uspace(buffer_ptr, ret.data.data, size);
855 if (rc == EOK)
856 rc = copy_to_uspace(size_ptr, &size, sizeof(size));
857
858 free(ret.data.data);
859 } else
860 rc = EINVAL;
861
862 return (sysarg_t) rc;
863}
864
[80bfb601]865/** Get the sysinfo value type (syscall)
866 *
867 * The path string passed from the user space has
868 * to be properly null-terminated (the last passed
869 * character must be null).
870 *
871 * @param path_ptr Sysinfo path in the user address space.
872 * @param path_size Size of the path string.
873 *
874 * @return Item value type.
875 *
876 */
[9a426d1f]877sysarg_t sys_sysinfo_get_val_type(void *path_ptr, size_t path_size)
[d9fae235]878{
[b4ad39f]879 /*
880 * Get the item.
881 *
882 * N.B.: There is no need to free any potential generated
883 * binary data since we request a dry run.
884 */
[70e2b2d]885 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
[9dae191e]886
[b4ad39f]887 /*
[3d23553]888 * Map generated value types to constant types (user space does
889 * not care whether the value is constant or generated).
[b4ad39f]890 */
[9dae191e]891 if (ret.tag == SYSINFO_VAL_FUNCTION_VAL)
892 ret.tag = SYSINFO_VAL_VAL;
893 else if (ret.tag == SYSINFO_VAL_FUNCTION_DATA)
894 ret.tag = SYSINFO_VAL_DATA;
895
[96b02eb9]896 return (sysarg_t) ret.tag;
[d9fae235]897}
[5719f6d]898
[80bfb601]899/** Get the sysinfo numerical value (syscall)
900 *
901 * The path string passed from the user space has
902 * to be properly null-terminated (the last passed
903 * character must be null).
904 *
905 * @param path_ptr Sysinfo path in the user address space.
906 * @param path_size Size of the path string.
907 * @param value_ptr User space pointer where to store the
908 * numberical value.
909 *
910 * @return Error code (EOK in case of no error).
911 *
912 */
[96b02eb9]913sysarg_t sys_sysinfo_get_value(void *path_ptr, size_t path_size,
[d9fae235]914 void *value_ptr)
[35a96cf]915{
[9dae191e]916 int rc;
[3d23553]917
[b4ad39f]918 /*
919 * Get the item.
920 *
[3d23553]921 * N.B.: There is no need to free any potential generated binary
922 * data since we request a dry run.
[b4ad39f]923 */
924 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
[d9fae235]925
[80bfb601]926 /* Only constant or generated numerical value is returned */
[9dae191e]927 if ((ret.tag == SYSINFO_VAL_VAL) || (ret.tag == SYSINFO_VAL_FUNCTION_VAL))
928 rc = copy_to_uspace(value_ptr, &ret.val, sizeof(ret.val));
929 else
930 rc = EINVAL;
[d9fae235]931
[96b02eb9]932 return (sysarg_t) rc;
[d9fae235]933}
[5719f6d]934
[80bfb601]935/** Get the sysinfo binary data size (syscall)
936 *
937 * The path string passed from the user space has
938 * to be properly null-terminated (the last passed
939 * character must be null).
940 *
941 * @param path_ptr Sysinfo path in the user address space.
942 * @param path_size Size of the path string.
943 * @param size_ptr User space pointer where to store the
944 * binary data size.
945 *
946 * @return Error code (EOK in case of no error).
947 *
948 */
[96b02eb9]949sysarg_t sys_sysinfo_get_data_size(void *path_ptr, size_t path_size,
[d9fae235]950 void *size_ptr)
951{
[b4ad39f]952 int rc;
[70e2b2d]953
[b4ad39f]954 /*
955 * Get the item.
956 *
[3d23553]957 * N.B.: There is no need to free any potential generated binary
958 * data since we request a dry run.
[b4ad39f]959 */
[70e2b2d]960 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
[9dae191e]961
[80bfb601]962 /* Only the size of constant or generated binary data is considered */
[9dae191e]963 if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA))
964 rc = copy_to_uspace(size_ptr, &ret.data.size,
965 sizeof(ret.data.size));
966 else
967 rc = EINVAL;
[749122b]968
[96b02eb9]969 return (sysarg_t) rc;
[35a96cf]970}
971
[80bfb601]972/** Get the sysinfo binary data (syscall)
973 *
974 * The path string passed from the user space has
975 * to be properly null-terminated (the last passed
976 * character must be null).
977 *
[311bc25]978 * If the user space buffer size does not equal
979 * the actual size of the returned data, the data
980 * is truncated. Whether this is actually a fatal
981 * error or the data can be still interpreted as valid
982 * depends on the nature of the data and has to be
983 * decided by the user space.
984 *
985 * The actual size of data returned is stored to
986 * size_ptr.
[80bfb601]987 *
988 * @param path_ptr Sysinfo path in the user address space.
989 * @param path_size Size of the path string.
990 * @param buffer_ptr User space pointer to the buffer where
991 * to store the binary data.
992 * @param buffer_size User space buffer size.
[311bc25]993 * @param size_ptr User space pointer where to store the
994 * binary data size.
[80bfb601]995 *
996 * @return Error code (EOK in case of no error).
997 *
998 */
[96b02eb9]999sysarg_t sys_sysinfo_get_data(void *path_ptr, size_t path_size,
[311bc25]1000 void *buffer_ptr, size_t buffer_size, size_t *size_ptr)
[35a96cf]1001{
[b4ad39f]1002 int rc;
[9dae191e]1003
[80bfb601]1004 /* Get the item */
[311bc25]1005 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size,
1006 false);
1007
[80bfb601]1008 /* Only constant or generated binary data is considered */
[311bc25]1009 if ((ret.tag == SYSINFO_VAL_DATA) ||
1010 (ret.tag == SYSINFO_VAL_FUNCTION_DATA)) {
1011 size_t size = min(ret.data.size, buffer_size);
1012 rc = copy_to_uspace(buffer_ptr, ret.data.data, size);
1013 if (rc == EOK)
1014 rc = copy_to_uspace(size_ptr, &size, sizeof(size));
[9dae191e]1015 } else
1016 rc = EINVAL;
[5719f6d]1017
[80bfb601]1018 /* N.B.: The generated binary data should be freed */
[9dae191e]1019 if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
1020 free(ret.data.data);
[749122b]1021
[96b02eb9]1022 return (sysarg_t) rc;
[35a96cf]1023}
[b45c443]1024
[cc73a8a1]1025/** @}
[b45c443]1026 */
Note: See TracBrowser for help on using the repository browser.