source: mainline/kernel/generic/src/sysinfo/sysinfo.c@ 70e2b2d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 70e2b2d was 70e2b2d, checked in by Martin Decky <martin@…>, 15 years ago

avoid costly allocation and generation of data when it is actually not necessary

  • Property mode set to 100644
File size: 22.0 KB
RevLine 
[6326f5e6]1/*
[df4ed85]2 * Copyright (c) 2006 Jakub Vana
[6326f5e6]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[a71c158]29/** @addtogroup generic
[b45c443]30 * @{
31 */
32/** @file
33 */
34
[2666daa]35#include <sysinfo/sysinfo.h>
36#include <mm/slab.h>
37#include <print.h>
[35a96cf]38#include <syscall/copy.h>
[9dae191e]39#include <synch/spinlock.h>
[a80687e5]40#include <arch/asm.h>
[d9fae235]41#include <errno.h>
42
[80bfb601]43/** Maximal sysinfo path length */
[d9fae235]44#define SYSINFO_MAX_PATH 2048
[2666daa]45
[a71c158]46bool fb_exported = false;
[2666daa]47
[80bfb601]48/** Global sysinfo tree root item */
[d9fae235]49static sysinfo_item_t *global_root = NULL;
[80bfb601]50
51/** Sysinfo SLAB cache */
[d9fae235]52static slab_cache_t *sysinfo_item_slab;
53
[80bfb601]54/** Sysinfo spinlock */
[9dae191e]55SPINLOCK_STATIC_INITIALIZE_NAME(sysinfo_lock, "sysinfo_lock");
56
[80bfb601]57/** Sysinfo item constructor
58 *
59 */
[d9fae235]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;
[b658c5d]67 item->subtree.table = NULL;
[d9fae235]68 item->next = NULL;
69
70 return 0;
71}
72
[80bfb601]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 */
[d9fae235]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
[80bfb601]90/** Initialize sysinfo subsystem
91 *
92 * Create SLAB cache for sysinfo items.
93 *
94 */
[d9fae235]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
[80bfb601]102/** Recursively find an item in sysinfo tree
[9dae191e]103 *
104 * Should be called with interrupts disabled
105 * and sysinfo_lock held.
106 *
[80bfb601]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 *
115 * @return Found item or NULL if no item in the fixed tree
116 * was found (N.B. ret).
117 *
[9dae191e]118 */
[d9fae235]119static sysinfo_item_t *sysinfo_find_item(const char *name,
[9dae191e]120 sysinfo_item_t *subtree, sysinfo_return_t **ret)
[2666daa]121{
[9dae191e]122 ASSERT(subtree != NULL);
123 ASSERT(ret != NULL);
124
[d9fae235]125 sysinfo_item_t *cur = subtree;
[749122b]126
[80bfb601]127 /* Walk all siblings */
[d9fae235]128 while (cur != NULL) {
129 size_t i = 0;
[749122b]130
[d9fae235]131 /* Compare name with path */
132 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
[749122b]133 i++;
134
[d9fae235]135 /* Check for perfect name and path match */
136 if ((name[i] == 0) && (cur->name[i] == 0))
137 return cur;
[749122b]138
[d9fae235]139 /* Partial match up to the delimiter */
140 if ((name[i] == '.') && (cur->name[i] == 0)) {
141 /* Look into the subtree */
142 switch (cur->subtree_type) {
143 case SYSINFO_SUBTREE_TABLE:
144 /* Recursively find in subtree */
[9dae191e]145 return sysinfo_find_item(name + i + 1,
146 cur->subtree.table, ret);
[d9fae235]147 case SYSINFO_SUBTREE_FUNCTION:
[9dae191e]148 /* Get generated data */
149 **ret = cur->subtree.get_data(name + i + 1);
150 return NULL;
[d9fae235]151 default:
[80bfb601]152 /* Not found, no data generated */
[9dae191e]153 *ret = NULL;
[d9fae235]154 return NULL;
155 }
[2666daa]156 }
[d9fae235]157
158 cur = cur->next;
[2666daa]159 }
[d9fae235]160
[80bfb601]161 /* Not found, no data generated */
[9dae191e]162 *ret = NULL;
[2666daa]163 return NULL;
164}
165
[9dae191e]166/** Recursively create items in sysinfo tree
167 *
168 * Should be called with interrupts disabled
169 * and sysinfo_lock held.
170 *
[80bfb601]171 * @param name Current sysinfo path suffix.
172 * @param psubtree Pointer to an already existing (sub)tree root
173 * item or where to store a new tree root item.
174 *
175 * @return Existing or newly allocated sysinfo item or NULL
176 * if the current tree configuration does not allow to
177 * create a new item.
178 *
[9dae191e]179 */
[d9fae235]180static sysinfo_item_t *sysinfo_create_path(const char *name,
181 sysinfo_item_t **psubtree)
[2666daa]182{
[b658c5d]183 ASSERT(psubtree != NULL);
184
[d9fae235]185 if (*psubtree == NULL) {
186 /* No parent */
187
188 size_t i = 0;
189
190 /* Find the first delimiter in name */
191 while ((name[i] != 0) && (name[i] != '.'))
[7bb6b06]192 i++;
[d9fae235]193
194 *psubtree =
195 (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
196 ASSERT(*psubtree);
197
198 /* Fill in item name up to the delimiter */
199 (*psubtree)->name = str_ndup(name, i);
200 ASSERT((*psubtree)->name);
201
202 /* Create subtree items */
203 if (name[i] == '.') {
204 (*psubtree)->subtree_type = SYSINFO_SUBTREE_TABLE;
205 return sysinfo_create_path(name + i + 1,
206 &((*psubtree)->subtree.table));
[7bb6b06]207 }
[d9fae235]208
209 /* No subtree needs to be created */
210 return *psubtree;
[2666daa]211 }
[d9fae235]212
213 sysinfo_item_t *cur = *psubtree;
214
[80bfb601]215 /* Walk all siblings */
[d9fae235]216 while (cur != NULL) {
217 size_t i = 0;
[749122b]218
[d9fae235]219 /* Compare name with path */
220 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
[749122b]221 i++;
222
[d9fae235]223 /* Check for perfect name and path match
224 * -> item is already present.
225 */
226 if ((name[i] == 0) && (cur->name[i] == 0))
227 return cur;
[749122b]228
[d9fae235]229 /* Partial match up to the delimiter */
230 if ((name[i] == '.') && (cur->name[i] == 0)) {
231 switch (cur->subtree_type) {
232 case SYSINFO_SUBTREE_NONE:
233 /* No subtree yet, create one */
234 cur->subtree_type = SYSINFO_SUBTREE_TABLE;
235 return sysinfo_create_path(name + i + 1,
236 &(cur->subtree.table));
237 case SYSINFO_SUBTREE_TABLE:
238 /* Subtree already created, add new sibling */
239 return sysinfo_create_path(name + i + 1,
240 &(cur->subtree.table));
241 default:
242 /* Subtree items handled by a function, this
[80bfb601]243 * cannot be overriden by a constant item.
[d9fae235]244 */
245 return NULL;
[749122b]246 }
[2666daa]247 }
[d9fae235]248
249 /* No match and no more siblings to check
250 * -> create a new sibling item.
251 */
252 if (cur->next == NULL) {
253 /* Find the first delimiter in name */
[749122b]254 i = 0;
[d9fae235]255 while ((name[i] != 0) && (name[i] != '.'))
[749122b]256 i++;
257
[d9fae235]258 sysinfo_item_t *item =
259 (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
260 ASSERT(item);
[749122b]261
[d9fae235]262 cur->next = item;
263
264 /* Fill in item name up to the delimiter */
265 item->name = str_ndup(name, i);
266 ASSERT(item->name);
267
268 /* Create subtree items */
269 if (name[i] == '.') {
270 item->subtree_type = SYSINFO_SUBTREE_TABLE;
271 return sysinfo_create_path(name + i + 1,
272 &(item->subtree.table));
[2666daa]273 }
[d9fae235]274
275 /* No subtree needs to be created */
[2666daa]276 return item;
[d9fae235]277 }
278
279 cur = cur->next;
[2666daa]280 }
[d9fae235]281
282 /* Unreachable */
283 ASSERT(false);
[2666daa]284 return NULL;
285}
286
[80bfb601]287/** Set sysinfo item with a constant numeric value
288 *
289 * @param name Sysinfo path.
290 * @param root Pointer to the root item or where to store
291 * a new root item (NULL for global sysinfo root).
292 * @param val Value to store in the item.
293 *
294 */
[d9fae235]295void sysinfo_set_item_val(const char *name, sysinfo_item_t **root,
296 unative_t val)
[2666daa]297{
[80bfb601]298 /* Protect sysinfo tree consistency */
[9dae191e]299 ipl_t ipl = interrupts_disable();
300 spinlock_lock(&sysinfo_lock);
301
[749122b]302 if (root == NULL)
[d9fae235]303 root = &global_root;
[749122b]304
305 sysinfo_item_t *item = sysinfo_create_path(name, root);
[d9fae235]306 if (item != NULL) {
[749122b]307 item->val_type = SYSINFO_VAL_VAL;
[d9fae235]308 item->val.val = val;
[749122b]309 }
[9dae191e]310
311 spinlock_unlock(&sysinfo_lock);
312 interrupts_restore(ipl);
[2666daa]313}
314
[80bfb601]315/** Set sysinfo item with a constant binary data
316 *
317 * Note that sysinfo only stores the pointer to the
318 * binary data and does not touch it in any way. The
319 * data should be static and immortal.
320 *
321 * @param name Sysinfo path.
322 * @param root Pointer to the root item or where to store
323 * a new root item (NULL for global sysinfo root).
324 * @param data Binary data.
325 * @param size Size of the binary data.
326 *
327 */
[d9fae235]328void sysinfo_set_item_data(const char *name, sysinfo_item_t **root,
329 void *data, size_t size)
[2666daa]330{
[80bfb601]331 /* Protect sysinfo tree consistency */
[9dae191e]332 ipl_t ipl = interrupts_disable();
333 spinlock_lock(&sysinfo_lock);
334
[749122b]335 if (root == NULL)
[d9fae235]336 root = &global_root;
[749122b]337
338 sysinfo_item_t *item = sysinfo_create_path(name, root);
[d9fae235]339 if (item != NULL) {
340 item->val_type = SYSINFO_VAL_DATA;
341 item->val.data.data = data;
342 item->val.data.size = size;
343 }
[9dae191e]344
345 spinlock_unlock(&sysinfo_lock);
346 interrupts_restore(ipl);
[d9fae235]347}
348
[80bfb601]349/** Set sysinfo item with a generated numeric value
350 *
351 * @param name Sysinfo path.
352 * @param root Pointer to the root item or where to store
353 * a new root item (NULL for global sysinfo root).
354 * @param fn Numeric value generator function.
355 *
356 */
[9dae191e]357void sysinfo_set_item_fn_val(const char *name, sysinfo_item_t **root,
[d9fae235]358 sysinfo_fn_val_t fn)
359{
[80bfb601]360 /* Protect sysinfo tree consistency */
[9dae191e]361 ipl_t ipl = interrupts_disable();
362 spinlock_lock(&sysinfo_lock);
363
[d9fae235]364 if (root == NULL)
365 root = &global_root;
[749122b]366
[d9fae235]367 sysinfo_item_t *item = sysinfo_create_path(name, root);
368 if (item != NULL) {
369 item->val_type = SYSINFO_VAL_FUNCTION_VAL;
370 item->val.fn_val = fn;
[749122b]371 }
[9dae191e]372
373 spinlock_unlock(&sysinfo_lock);
374 interrupts_restore(ipl);
[2666daa]375}
376
[80bfb601]377/** Set sysinfo item with a generated binary data
378 *
379 * Note that each time the generator function is called
380 * it is supposed to return a new dynamically allocated
381 * data. This data is then freed by sysinfo in the context
382 * of the current sysinfo request.
383 *
384 * @param name Sysinfo path.
385 * @param root Pointer to the root item or where to store
386 * a new root item (NULL for global sysinfo root).
387 * @param fn Binary data generator function.
388 *
389 */
[9dae191e]390void sysinfo_set_item_fn_data(const char *name, sysinfo_item_t **root,
[d9fae235]391 sysinfo_fn_data_t fn)
392{
[80bfb601]393 /* Protect sysinfo tree consistency */
[9dae191e]394 ipl_t ipl = interrupts_disable();
395 spinlock_lock(&sysinfo_lock);
396
[d9fae235]397 if (root == NULL)
398 root = &global_root;
399
400 sysinfo_item_t *item = sysinfo_create_path(name, root);
401 if (item != NULL) {
402 item->val_type = SYSINFO_VAL_FUNCTION_DATA;
403 item->val.fn_data = fn;
404 }
[9dae191e]405
406 spinlock_unlock(&sysinfo_lock);
407 interrupts_restore(ipl);
[d9fae235]408}
[2666daa]409
[80bfb601]410/** Set sysinfo item with an undefined value
411 *
412 * @param name Sysinfo path.
413 * @param root Pointer to the root item or where to store
414 * a new root item (NULL for global sysinfo root).
415 *
416 */
[749122b]417void sysinfo_set_item_undefined(const char *name, sysinfo_item_t **root)
[2666daa]418{
[80bfb601]419 /* Protect sysinfo tree consistency */
[9dae191e]420 ipl_t ipl = interrupts_disable();
421 spinlock_lock(&sysinfo_lock);
422
[749122b]423 if (root == NULL)
[d9fae235]424 root = &global_root;
[749122b]425
426 sysinfo_item_t *item = sysinfo_create_path(name, root);
427 if (item != NULL)
428 item->val_type = SYSINFO_VAL_UNDEFINED;
[9dae191e]429
430 spinlock_unlock(&sysinfo_lock);
431 interrupts_restore(ipl);
[2666daa]432}
433
[80bfb601]434/** Set sysinfo item with a generated subtree
435 *
436 * @param name Sysinfo path.
437 * @param root Pointer to the root item or where to store
438 * a new root item (NULL for global sysinfo root).
439 * @param fn Subtree generator function.
440 *
441 */
[9dae191e]442void sysinfo_set_subtree_fn(const char *name, sysinfo_item_t **root,
443 sysinfo_fn_subtree_t fn)
444{
[80bfb601]445 /* Protect sysinfo tree consistency */
[9dae191e]446 ipl_t ipl = interrupts_disable();
447 spinlock_lock(&sysinfo_lock);
448
449 if (root == NULL)
450 root = &global_root;
451
452 sysinfo_item_t *item = sysinfo_create_path(name, root);
[80bfb601]453
454 /* Change the type of the subtree only if it is not already
455 a fixed subtree */
[9dae191e]456 if ((item != NULL) && (item->subtree_type != SYSINFO_SUBTREE_TABLE)) {
457 item->subtree_type = SYSINFO_SUBTREE_FUNCTION;
458 item->subtree.get_data = fn;
459 }
460
461 spinlock_unlock(&sysinfo_lock);
462 interrupts_restore(ipl);
463}
464
465/** Sysinfo dump indentation helper routine
[80bfb601]466 *
467 * @param depth Number of indentation characters to print.
[9dae191e]468 *
469 */
[d9fae235]470static void sysinfo_indent(unsigned int depth)
471{
472 unsigned int i;
473 for (i = 0; i < depth; i++)
474 printf(" ");
475}
[2666daa]476
[9dae191e]477/** Dump the structure of sysinfo tree
478 *
479 * Should be called with interrupts disabled
480 * and sysinfo_lock held. Because this routine
481 * might take a reasonable long time to proceed,
482 * having the spinlock held is not optimal, but
483 * there is no better simple solution.
484 *
[80bfb601]485 * @param root Root item of the current (sub)tree.
486 * @param depth Current depth in the sysinfo tree.
487 *
[9dae191e]488 */
489static void sysinfo_dump_internal(sysinfo_item_t *root, unsigned int depth)
[2666daa]490{
[9dae191e]491 sysinfo_item_t *cur = root;
[2666daa]492
[80bfb601]493 /* Walk all siblings */
[d9fae235]494 while (cur != NULL) {
495 sysinfo_indent(depth);
[2666daa]496
[d9fae235]497 unative_t val;
498 size_t size;
[2666daa]499
[80bfb601]500 /* Display node value and type */
[d9fae235]501 switch (cur->val_type) {
[f8ddd17]502 case SYSINFO_VAL_UNDEFINED:
[d9fae235]503 printf("+ %s\n", cur->name);
[f8ddd17]504 break;
505 case SYSINFO_VAL_VAL:
[d9fae235]506 printf("+ %s -> %" PRIun" (%#" PRIxn ")\n", cur->name,
507 cur->val.val, cur->val.val);
[f8ddd17]508 break;
[d9fae235]509 case SYSINFO_VAL_DATA:
510 printf("+ %s (%" PRIs" bytes)\n", cur->name,
511 cur->val.data.size);
[f8ddd17]512 break;
[d9fae235]513 case SYSINFO_VAL_FUNCTION_VAL:
514 val = cur->val.fn_val(cur);
515 printf("+ %s -> %" PRIun" (%#" PRIxn ") [generated]\n",
516 cur->name, val, val);
517 break;
518 case SYSINFO_VAL_FUNCTION_DATA:
[70e2b2d]519 /* N.B.: No data was actually returned (only a dry run) */
520 (void) cur->val.fn_data(cur, &size, true);
[d9fae235]521 printf("+ %s (%" PRIs" bytes) [generated]\n", cur->name,
522 size);
523 break;
524 default:
525 printf("+ %s [unknown]\n", cur->name);
[749122b]526 }
[2666daa]527
[80bfb601]528 /* Recursivelly nest into the subtree */
[d9fae235]529 switch (cur->subtree_type) {
530 case SYSINFO_SUBTREE_NONE:
531 break;
532 case SYSINFO_SUBTREE_TABLE:
[9dae191e]533 sysinfo_dump_internal(cur->subtree.table, depth + 1);
[d9fae235]534 break;
535 case SYSINFO_SUBTREE_FUNCTION:
536 sysinfo_indent(depth + 1);
[9dae191e]537 printf("+ [generated subtree]\n");
[d9fae235]538 break;
539 default:
540 sysinfo_indent(depth + 1);
[9dae191e]541 printf("+ [unknown subtree]\n");
[d9fae235]542 }
[2666daa]543
[d9fae235]544 cur = cur->next;
[749122b]545 }
[2666daa]546}
547
[80bfb601]548/** Dump the structure of sysinfo tree
549 *
550 * @param root Root item of the sysinfo (sub)tree.
551 * If it is NULL then consider the global
552 * sysinfo tree.
553 *
554 */
[9dae191e]555void sysinfo_dump(sysinfo_item_t *root)
556{
[80bfb601]557 /* Avoid other functions to mess with sysinfo
558 while we are dumping it */
[9dae191e]559 ipl_t ipl = interrupts_disable();
560 spinlock_lock(&sysinfo_lock);
561
562 if (root == NULL)
563 sysinfo_dump_internal(global_root, 0);
564 else
565 sysinfo_dump_internal(root, 0);
566
567 spinlock_unlock(&sysinfo_lock);
568 interrupts_restore(ipl);
569}
570
[80bfb601]571/** Return sysinfo item value determined by name
[9dae191e]572 *
573 * Should be called with interrupts disabled
574 * and sysinfo_lock held.
575 *
[70e2b2d]576 * @param name Sysinfo path.
577 * @param root Root item of the sysinfo (sub)tree.
578 * If it is NULL then consider the global
579 * sysinfo tree.
580 * @param dry_run Do not actually get any generated
581 * binary data, just calculate the size.
[80bfb601]582 *
583 * @return Item value (constant or generated).
584 *
[9dae191e]585 */
[70e2b2d]586static sysinfo_return_t sysinfo_get_item(const char *name,
587 sysinfo_item_t **root, bool dry_run)
[2666daa]588{
[749122b]589 if (root == NULL)
[d9fae235]590 root = &global_root;
[749122b]591
[80bfb601]592 /* Try to find the item or generate data */
[d9fae235]593 sysinfo_return_t ret;
[9dae191e]594 sysinfo_return_t *ret_ptr = &ret;
595 sysinfo_item_t *item = sysinfo_find_item(name, *root, &ret_ptr);
[749122b]596
597 if (item != NULL) {
[80bfb601]598 /* Item found in the fixed sysinfo tree */
599
[9dae191e]600 ret.tag = item->val_type;
[d9fae235]601 switch (item->val_type) {
602 case SYSINFO_VAL_UNDEFINED:
603 break;
604 case SYSINFO_VAL_VAL:
[749122b]605 ret.val = item->val.val;
[d9fae235]606 break;
607 case SYSINFO_VAL_DATA:
608 ret.data = item->val.data;
609 break;
610 case SYSINFO_VAL_FUNCTION_VAL:
611 ret.val = item->val.fn_val(item);
612 break;
613 case SYSINFO_VAL_FUNCTION_DATA:
[70e2b2d]614 ret.data.data = item->val.fn_data(item, &ret.data.size,
615 dry_run);
[d9fae235]616 break;
617 }
[9dae191e]618 } else {
[80bfb601]619 /* No item in the fixed sysinfo tree */
620 if (ret_ptr == NULL) {
621 /* Even no data was generated */
[9dae191e]622 ret.tag = SYSINFO_VAL_UNDEFINED;
[80bfb601]623 }
[9dae191e]624 }
[d9fae235]625
626 return ret;
627}
628
[9dae191e]629/** Return sysinfo item determined by name from user space
630 *
631 * Should be called with interrupts disabled
[80bfb601]632 * and sysinfo_lock held. The path string passed from
633 * the user space has to be properly null-terminated
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 */
[70e2b2d]642static sysinfo_return_t sysinfo_get_item_uspace(void *ptr, size_t size,
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);
652 ASSERT(path);
653
654 if ((copy_from_uspace(path, ptr, size + 1) == 0)
[9dae191e]655 && (path[size] == 0))
[70e2b2d]656 ret = sysinfo_get_item(path, NULL, dry_run);
[d9fae235]657
[9dae191e]658 free(path);
[2666daa]659 return ret;
660}
[35a96cf]661
[80bfb601]662/** Get the sysinfo value type (syscall)
663 *
664 * The path string passed from the user space has
665 * to be properly null-terminated (the last passed
666 * character must be null).
667 *
668 * @param path_ptr Sysinfo path in the user address space.
669 * @param path_size Size of the path string.
670 *
671 * @return Item value type.
672 *
673 */
[d9fae235]674unative_t sys_sysinfo_get_tag(void *path_ptr, size_t path_size)
675{
[80bfb601]676 /* Avoid other functions to mess with sysinfo
677 while we are reading it */
[9dae191e]678 ipl_t ipl = interrupts_disable();
679 spinlock_lock(&sysinfo_lock);
680
[70e2b2d]681 /* Get the item.
[9dae191e]682
[70e2b2d]683 N.B.: There is no need to free any potential generated
684 binary data since we request a dry run */
685 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
[9dae191e]686
[80bfb601]687 /* Map generated value types to constant types
688 (user space does not care whether the
689 value is constant or generated) */
[9dae191e]690 if (ret.tag == SYSINFO_VAL_FUNCTION_VAL)
691 ret.tag = SYSINFO_VAL_VAL;
692 else if (ret.tag == SYSINFO_VAL_FUNCTION_DATA)
693 ret.tag = SYSINFO_VAL_DATA;
694
695 spinlock_unlock(&sysinfo_lock);
696 interrupts_restore(ipl);
697
698 return (unative_t) ret.tag;
[d9fae235]699}
[5719f6d]700
[80bfb601]701/** Get the sysinfo numerical value (syscall)
702 *
703 * The path string passed from the user space has
704 * to be properly null-terminated (the last passed
705 * character must be null).
706 *
707 * @param path_ptr Sysinfo path in the user address space.
708 * @param path_size Size of the path string.
709 * @param value_ptr User space pointer where to store the
710 * numberical value.
711 *
712 * @return Error code (EOK in case of no error).
713 *
714 */
[d9fae235]715unative_t sys_sysinfo_get_value(void *path_ptr, size_t path_size,
716 void *value_ptr)
[35a96cf]717{
[80bfb601]718 /* Avoid other functions to mess with sysinfo
719 while we are reading it */
[9dae191e]720 ipl_t ipl = interrupts_disable();
721 spinlock_lock(&sysinfo_lock);
722
[70e2b2d]723 /* Get the item.
724
725 N.B.: There is no need to free any potential generated
726 binary data since we request a dry run */
727 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
[9dae191e]728 int rc;
[d9fae235]729
[80bfb601]730 /* Only constant or generated numerical value is returned */
[9dae191e]731 if ((ret.tag == SYSINFO_VAL_VAL) || (ret.tag == SYSINFO_VAL_FUNCTION_VAL))
732 rc = copy_to_uspace(value_ptr, &ret.val, sizeof(ret.val));
733 else
734 rc = EINVAL;
[d9fae235]735
[9dae191e]736 spinlock_unlock(&sysinfo_lock);
737 interrupts_restore(ipl);
738
739 return (unative_t) rc;
[d9fae235]740}
[5719f6d]741
[80bfb601]742/** Get the sysinfo binary data size (syscall)
743 *
744 * The path string passed from the user space has
745 * to be properly null-terminated (the last passed
746 * character must be null).
747 *
748 * @param path_ptr Sysinfo path in the user address space.
749 * @param path_size Size of the path string.
750 * @param size_ptr User space pointer where to store the
751 * binary data size.
752 *
753 * @return Error code (EOK in case of no error).
754 *
755 */
[d9fae235]756unative_t sys_sysinfo_get_data_size(void *path_ptr, size_t path_size,
757 void *size_ptr)
758{
[80bfb601]759 /* Avoid other functions to mess with sysinfo
760 while we are reading it */
[9dae191e]761 ipl_t ipl = interrupts_disable();
762 spinlock_lock(&sysinfo_lock);
763
[70e2b2d]764 /* Get the item.
765
766 N.B.: There is no need to free any potential generated
767 binary data since we request a dry run */
768 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
[9dae191e]769 int rc;
770
[80bfb601]771 /* Only the size of constant or generated binary data is considered */
[9dae191e]772 if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA))
773 rc = copy_to_uspace(size_ptr, &ret.data.size,
774 sizeof(ret.data.size));
775 else
776 rc = EINVAL;
[749122b]777
[9dae191e]778 spinlock_unlock(&sysinfo_lock);
779 interrupts_restore(ipl);
780
781 return (unative_t) rc;
[35a96cf]782}
783
[80bfb601]784/** Get the sysinfo binary data (syscall)
785 *
786 * The path string passed from the user space has
787 * to be properly null-terminated (the last passed
788 * character must be null).
789 *
790 * The user space buffer must be sized exactly according
791 * to the size of the binary data, otherwise the request
792 * fails.
793 *
794 * @param path_ptr Sysinfo path in the user address space.
795 * @param path_size Size of the path string.
796 * @param buffer_ptr User space pointer to the buffer where
797 * to store the binary data.
798 * @param buffer_size User space buffer size.
799 *
800 * @return Error code (EOK in case of no error).
801 *
802 */
[d9fae235]803unative_t sys_sysinfo_get_data(void *path_ptr, size_t path_size,
804 void *buffer_ptr, size_t buffer_size)
[35a96cf]805{
[80bfb601]806 /* Avoid other functions to mess with sysinfo
807 while we are reading it */
[9dae191e]808 ipl_t ipl = interrupts_disable();
809 spinlock_lock(&sysinfo_lock);
810
[80bfb601]811 /* Get the item */
[70e2b2d]812 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, false);
[9dae191e]813 int rc;
814
[80bfb601]815 /* Only constant or generated binary data is considered */
[9dae191e]816 if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA)) {
[80bfb601]817 /* Check destination buffer size */
[9dae191e]818 if (ret.data.size == buffer_size)
819 rc = copy_to_uspace(buffer_ptr, ret.data.data,
820 ret.data.size);
821 else
822 rc = ENOMEM;
823 } else
824 rc = EINVAL;
[5719f6d]825
[80bfb601]826 /* N.B.: The generated binary data should be freed */
[9dae191e]827 if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
828 free(ret.data.data);
[749122b]829
[9dae191e]830 spinlock_unlock(&sysinfo_lock);
831 interrupts_restore(ipl);
[749122b]832
[9dae191e]833 return (unative_t) rc;
[35a96cf]834}
[b45c443]835
[cc73a8a1]836/** @}
[b45c443]837 */
Note: See TracBrowser for help on using the repository browser.