VirtualBox

source: vbox/trunk/src/VBox/VMM/CFGM.cpp@ 7796

Last change on this file since 7796 was 7759, checked in by vboxsync, 17 years ago

The BIOS logo stuff moved to VGA device. Added 24bpp bitmaps support.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 57.0 KB
Line 
1/* $Id: CFGM.cpp 7759 2008-04-05 11:36:02Z vboxsync $ */
2/** @file
3 * CFGM - Configuration Manager.
4 *
5 * This is the main file of the \ref pg_cfgm "CFGM (Configuration Manager)".
6 */
7
8/*
9 * Copyright (C) 2006-2007 innotek GmbH
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/** @page pg_cfgm CFGM - The Configuration Manager
21 *
22 * The configuration manager will load and keep the configuration of a VM
23 * handy (thru query interface) while the VM is running. The VM properties
24 * are organized in a tree and individual nodes can be accessed by normal
25 * path walking.
26 *
27 * Exactly how the CFGM obtains the configuration is specific to the build.
28 * The default for a full build is to query it thru the IMachine interface and
29 * applies it onto a default setup. It's necessary to have a default in the
30 * bottom of this because the IMachine interface doesn't provide all the
31 * required details.
32 *
33 * Devices are given their own subtree where they are protected from accessing
34 * information of any parents. The exported PDM callback interfaces makes sure
35 * of this.
36 *
37 * Validating of the data obtained, except for validation of the primitive type,
38 * is all up to the user. The CFGM user is concidered in a better position to
39 * know the validation rules of the individual properties.
40 *
41 *
42 * @section sec_cfgm_primitives Data Primitives
43 *
44 * CFGM supports the following data primitives:
45 * - Integers. Representation is signed 64-bit. Boolean, unsigned and
46 * small integers are all represented using this primitive.
47 * - Zero terminated character strings. As everywhere else
48 * strings are UTF-8.
49 * - Variable length byte strings. This can be used to get/put binary
50 * objects.
51 *
52 */
53
54
55/*******************************************************************************
56* Header Files *
57*******************************************************************************/
58#define LOG_GROUP LOG_GROUP_CFGM
59#include <VBox/cfgm.h>
60#include <VBox/dbgf.h>
61#include <VBox/mm.h>
62#include "CFGMInternal.h"
63#include <VBox/vm.h>
64#include <VBox/err.h>
65
66#include <VBox/log.h>
67#include <iprt/assert.h>
68#include <iprt/string.h>
69#include <iprt/uuid.h>
70
71
72/*******************************************************************************
73* Internal Functions *
74*******************************************************************************/
75static int cfgmR3CreateDefault(PVM pVM);
76static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp);
77static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp);
78static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
79static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild);
80static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
81static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
82static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf);
83static void cfgmR3FreeValue(PCFGMLEAF pLeaf);
84
85
86
87/**
88 * Constructs the configuration for the VM.
89 *
90 * @returns VBox status code.
91 * @param pVM Pointer to VM which configuration has not yet been loaded.
92 * @param pfnCFGMConstructor Pointer to callback function for constructing the VM configuration tree.
93 * This is called in the EM.
94 * @param pvUser The user argument passed to pfnCFGMConstructor.
95 */
96CFGMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUser)
97{
98 LogFlow(("CFGMR3Init: pfnCFGMConstructor=%p pvUser=%p\n", pfnCFGMConstructor, pvUser));
99
100 /*
101 * Init data members.
102 */
103 pVM->cfgm.s.offVM = RT_OFFSETOF(VM, cfgm);
104 pVM->cfgm.s.pRoot = NULL;
105
106 /*
107 * Register DBGF into item.
108 */
109 int rc = DBGFR3InfoRegisterInternal(pVM, "cfgm", "Dumps a part of the CFGM tree. The argument indicates where to start.", cfgmR3Info);
110 AssertRCReturn(rc,rc);
111
112 /*
113 * Create the configuration tree.
114 */
115 if (pfnCFGMConstructor)
116 {
117 /*
118 * Root Node.
119 */
120 PCFGMNODE pRoot = (PCFGMNODE)MMR3HeapAllocZ(pVM, MM_TAG_CFGM, sizeof(*pRoot));
121 if (!pRoot)
122 return VERR_NO_MEMORY;
123 pRoot->pVM = pVM;
124 pRoot->cchName = 0;
125 pVM->cfgm.s.pRoot = pRoot;
126
127 /*
128 * Call the constructor.
129 */
130 rc = pfnCFGMConstructor(pVM, pvUser);
131 }
132 else
133 rc = cfgmR3CreateDefault(pVM);
134 if (VBOX_SUCCESS(rc))
135 {
136 Log(("CFGMR3Init: Successfully constructed the configuration\n"));
137 CFGMR3Dump(CFGMR3GetRoot(pVM));
138
139 }
140 else
141 NoDmik(AssertMsgFailed(("Constructor failed with rc=%Vrc pfnCFGMConstructor=%p\n", rc, pfnCFGMConstructor)));
142
143 return rc;
144}
145
146
147/**
148 * Terminates the configuration manager.
149 *
150 * @returns VBox status code.
151 * @param pVM VM handle.
152 */
153CFGMR3DECL(int) CFGMR3Term(PVM pVM)
154{
155 CFGMR3RemoveNode(pVM->cfgm.s.pRoot);
156 return 0;
157}
158
159
160/**
161 * Gets the root node for the VM.
162 *
163 * @returns Pointer to root node.
164 * @param pVM VM handle.
165 */
166CFGMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM)
167{
168 return pVM->cfgm.s.pRoot;
169}
170
171
172/**
173 * Gets the parent of a CFGM node.
174 *
175 * @returns Pointer to the parent node.
176 * @returns NULL if pNode is Root or pNode is the start of a
177 * restricted subtree (use CFGMr3GetParentEx() for that).
178 *
179 * @param pNode The node which parent we query.
180 */
181CFGMR3DECL(PCFGMNODE) CFGMR3GetParent(PCFGMNODE pNode)
182{
183 if (pNode && !pNode->fRestrictedRoot)
184 return pNode->pParent;
185 return NULL;
186}
187
188
189/**
190 * Gets the parent of a CFGM node.
191 *
192 * @returns Pointer to the parent node.
193 * @returns NULL if pNode is Root or pVM is not correct.
194 *
195 * @param pVM The VM handle, used as token that the caller is trusted.
196 * @param pNode The node which parent we query.
197 */
198CFGMR3DECL(PCFGMNODE) CFGMR3GetParentEx(PVM pVM, PCFGMNODE pNode)
199{
200 if (pNode && pNode->pVM == pVM)
201 return pNode->pParent;
202 return NULL;
203}
204
205
206/**
207 * Query a child node.
208 *
209 * @returns Pointer to the specified node.
210 * @returns NULL if node was not found or pNode is NULL.
211 * @param pNode Node pszPath is relative to.
212 * @param pszPath Path to the child node or pNode.
213 * It's good style to end this with '/'.
214 */
215CFGMR3DECL(PCFGMNODE) CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath)
216{
217 PCFGMNODE pChild;
218 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
219 if (VBOX_SUCCESS(rc))
220 return pChild;
221 return NULL;
222}
223
224
225/**
226 * Query a child node by a format string.
227 *
228 * @returns Pointer to the specified node.
229 * @returns NULL if node was not found or pNode is NULL.
230 * @param pNode Node pszPath is relative to.
231 * @param pszPathFormat Path to the child node or pNode.
232 * It's good style to end this with '/'.
233 * @param ... Arguments to pszPathFormat.
234 */
235CFGMR3DECL(PCFGMNODE) CFGMR3GetChildF(PCFGMNODE pNode, const char *pszPathFormat, ...)
236{
237 va_list Args;
238 va_start(Args, pszPathFormat);
239 PCFGMNODE pRet = CFGMR3GetChildFV(pNode, pszPathFormat, Args);
240 va_end(Args);
241 return pRet;
242}
243
244
245/**
246 * Query a child node by a format string.
247 *
248 * @returns Pointer to the specified node.
249 * @returns NULL if node was not found or pNode is NULL.
250 * @param pNode Node pszPath is relative to.
251 * @param pszPathFormat Path to the child node or pNode.
252 * It's good style to end this with '/'.
253 * @param Args Arguments to pszPathFormat.
254 */
255CFGMR3DECL(PCFGMNODE) CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args)
256{
257 char *pszPath;
258 RTStrAPrintfV(&pszPath, pszPathFormat, Args);
259 if (pszPath)
260 {
261 PCFGMNODE pChild;
262 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
263 if (VBOX_SUCCESS(rc))
264 return pChild;
265 RTStrFree(pszPath);
266 }
267 return NULL;
268}
269
270
271/**
272 * Gets the first child node.
273 * Use this to start an enumeration of child nodes.
274 *
275 * @returns Pointer to the first child.
276 * @returns NULL if no children.
277 * @param pNode Node to enumerate children for.
278 */
279CFGMR3DECL(PCFGMNODE) CFGMR3GetFirstChild(PCFGMNODE pNode)
280{
281 return pNode ? pNode->pFirstChild : NULL;
282}
283
284
285/**
286 * Gets the next sibling node.
287 * Use this to continue an enumeration.
288 *
289 * @returns Pointer to the first child.
290 * @returns NULL if no children.
291 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
292 * or successive calls to this function.
293 */
294CFGMR3DECL(PCFGMNODE) CFGMR3GetNextChild(PCFGMNODE pCur)
295{
296 return pCur ? pCur->pNext : NULL;
297}
298
299
300/**
301 * Gets the name of the current node.
302 * (Needed for enumeration.)
303 *
304 * @returns VBox status code.
305 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
306 * or successive calls to CFGMR3GetNextChild().
307 * @param pszName Where to store the node name.
308 * @param cchName Size of the buffer pointed to by pszName (with terminator).
309 */
310CFGMR3DECL(int) CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName)
311{
312 int rc;
313 if (pCur)
314 {
315 if (cchName > pCur->cchName)
316 {
317 rc = VINF_SUCCESS;
318 memcpy(pszName, pCur->szName, pCur->cchName + 1);
319 }
320 else
321 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
322 }
323 else
324 rc = VERR_CFGM_NO_NODE;
325 return rc;
326}
327
328
329/**
330 * Gets the length of the current node's name.
331 * (Needed for enumeration.)
332 *
333 * @returns Node name length in bytes including the terminating null char.
334 * @returns 0 if pCur is NULL.
335 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
336 * or successive calls to CFGMR3GetNextChild().
337 */
338CFGMR3DECL(int) CFGMR3GetNameLen(PCFGMNODE pCur)
339{
340 return pCur ? pCur->cchName + 1 : 0;
341}
342
343
344/**
345 * Validates that the child nodes are within a set of valid names.
346 *
347 * @returns true if all names are found in pszzAllowed.
348 * @returns false if not.
349 * @param pNode The node which children should be examined.
350 * @param pszzValid List of valid names separated by '\\0' and ending with
351 * a double '\\0'.
352 */
353CFGMR3DECL(bool) CFGMR3AreChildrenValid(PCFGMNODE pNode, const char *pszzValid)
354{
355 if (pNode)
356 {
357 for (PCFGMNODE pChild = pNode->pFirstChild; pChild; pChild = pChild->pNext)
358 {
359 /* search pszzValid for the name */
360 const char *psz = pszzValid;
361 while (*psz)
362 {
363 size_t cch = strlen(psz);
364 if ( cch == pChild->cchName
365 && !memcmp(psz, pChild->szName, cch))
366 break;
367
368 /* next */
369 psz += cch + 1;
370 }
371
372 /* if at end of pszzValid we didn't find it => failure */
373 if (!*psz)
374 {
375 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pChild->szName));
376 return false;
377 }
378 }
379 }
380
381 /* all ok. */
382 return true;
383}
384
385
386/**
387 * Gets the first value of a node.
388 * Use this to start an enumeration of values.
389 *
390 * @returns Pointer to the first value.
391 * @param pCur The node (Key) which values to enumerate.
392 */
393CFGMR3DECL(PCFGMLEAF) CFGMR3GetFirstValue(PCFGMNODE pCur)
394{
395 return pCur ? pCur->pFirstLeaf : NULL;
396}
397
398/**
399 * Gets the next value in enumeration.
400 *
401 * @returns Pointer to the next value.
402 * @param pCur The current value as returned by this function or CFGMR3GetFirstValue().
403 */
404CFGMR3DECL(PCFGMLEAF) CFGMR3GetNextValue(PCFGMLEAF pCur)
405{
406 return pCur ? pCur->pNext : NULL;
407}
408
409/**
410 * Get the value name.
411 * (Needed for enumeration.)
412 *
413 * @returns VBox status code.
414 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
415 * or successive calls to CFGMR3GetNextValue().
416 * @param pszName Where to store the value name.
417 * @param cchName Size of the buffer pointed to by pszName (with terminator).
418 */
419CFGMR3DECL(int) CFGMR3GetValueName(PCFGMLEAF pCur, char *pszName, size_t cchName)
420{
421 int rc;
422 if (pCur)
423 {
424 if (cchName > pCur->cchName)
425 {
426 rc = VINF_SUCCESS;
427 memcpy(pszName, pCur->szName, pCur->cchName + 1);
428 }
429 else
430 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
431 }
432 else
433 rc = VERR_CFGM_NO_NODE;
434 return rc;
435}
436
437
438/**
439 * Gets the length of the current node's name.
440 * (Needed for enumeration.)
441 *
442 * @returns Value name length in bytes including the terminating null char.
443 * @returns 0 if pCur is NULL.
444 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
445 * or successive calls to CFGMR3GetNextValue().
446 */
447CFGMR3DECL(int) CFGMR3GetValueNameLen(PCFGMLEAF pCur)
448{
449 return pCur ? pCur->cchName + 1 : 0;
450}
451
452/**
453 * Gets the value type.
454 * (For enumeration.)
455 *
456 * @returns VBox status code.
457 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
458 * or successive calls to CFGMR3GetNextValue().
459 */
460CFGMR3DECL(CFGMVALUETYPE) CFGMR3GetValueType(PCFGMLEAF pCur)
461{
462 Assert(pCur);
463 return pCur->enmType;
464}
465
466
467/**
468 * Validates that the values are within a set of valid names.
469 *
470 * @returns true if all names are found in pszzAllowed.
471 * @returns false if not.
472 * @param pNode The node which values should be examined.
473 * @param pszzValid List of valid names separated by '\\0' and ending with
474 * a double '\\0'.
475 */
476CFGMR3DECL(bool) CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid)
477{
478 if (pNode)
479 {
480 for (PCFGMLEAF pLeaf = pNode->pFirstLeaf; pLeaf; pLeaf = pLeaf->pNext)
481 {
482 /* search pszzValid for the name */
483 const char *psz = pszzValid;
484 while (*psz)
485 {
486 size_t cch = strlen(psz);
487 if ( cch == pLeaf->cchName
488 && !memcmp(psz, pLeaf->szName, cch))
489 break;
490
491 /* next */
492 psz += cch + 1;
493 }
494
495 /* if at end of pszzValid we didn't find it => failure */
496 if (!*psz)
497 {
498 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pLeaf->szName));
499 return false;
500 }
501 }
502 }
503
504 /* all ok. */
505 return true;
506}
507
508
509
510/**
511 * Query value type.
512 *
513 * @returns VBox status code.
514 * @param pNode Which node to search for pszName in.
515 * @param pszName Name of an integer value.
516 * @param penmType Where to store the type.
517 */
518CFGMR3DECL(int) CFGMR3QueryType(PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)
519{
520 PCFGMLEAF pLeaf;
521 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
522 if (VBOX_SUCCESS(rc))
523 {
524 if (penmType)
525 *penmType = pLeaf->enmType;
526 }
527 return rc;
528}
529
530
531/**
532 * Query value size.
533 * This works on all types of values.
534 *
535 * @returns VBox status code.
536 * @param pNode Which node to search for pszName in.
537 * @param pszName Name of an integer value.
538 * @param pcb Where to store the value size.
539 */
540CFGMR3DECL(int) CFGMR3QuerySize(PCFGMNODE pNode, const char *pszName, size_t *pcb)
541{
542 PCFGMLEAF pLeaf;
543 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
544 if (VBOX_SUCCESS(rc))
545 {
546 switch (pLeaf->enmType)
547 {
548 case CFGMVALUETYPE_INTEGER:
549 *pcb = sizeof(pLeaf->Value.Integer.u64);
550 break;
551
552 case CFGMVALUETYPE_STRING:
553 *pcb = pLeaf->Value.String.cch;
554 break;
555
556 case CFGMVALUETYPE_BYTES:
557 *pcb = pLeaf->Value.Bytes.cb;
558 break;
559
560 default:
561 rc = VERR_INTERNAL_ERROR;
562 AssertMsgFailed(("Invalid value type %d\n", pLeaf->enmType));
563 break;
564 }
565 }
566 return rc;
567}
568
569
570/**
571 * Query integer value.
572 *
573 * @returns VBox status code.
574 * @param pNode Which node to search for pszName in.
575 * @param pszName Name of an integer value.
576 * @param pu64 Where to store the integer value.
577 */
578CFGMR3DECL(int) CFGMR3QueryInteger(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
579{
580 PCFGMLEAF pLeaf;
581 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
582 if (VBOX_SUCCESS(rc))
583 {
584 if (pLeaf->enmType == CFGMVALUETYPE_INTEGER)
585 *pu64 = pLeaf->Value.Integer.u64;
586 else
587 rc = VERR_CFGM_NOT_INTEGER;
588 }
589 return rc;
590}
591
592
593/**
594 * Query zero terminated character value.
595 *
596 * @returns VBox status code.
597 * @param pNode Which node to search for pszName in.
598 * @param pszName Name of a zero terminate character value.
599 * @param pszString Where to store the string.
600 * @param cchString Size of the string buffer. (Includes terminator.)
601 */
602CFGMR3DECL(int) CFGMR3QueryString(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)
603{
604 PCFGMLEAF pLeaf;
605 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
606 if (VBOX_SUCCESS(rc))
607 {
608 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
609 {
610 if (cchString >= pLeaf->Value.String.cch)
611 {
612 memcpy(pszString, pLeaf->Value.String.psz, pLeaf->Value.String.cch);
613 memset(pszString + pLeaf->Value.String.cch, 0, cchString - pLeaf->Value.String.cch);
614 }
615 else
616 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
617 }
618 else
619 rc = VERR_CFGM_NOT_STRING;
620 }
621 return rc;
622}
623
624
625/**
626 * Query byte string value.
627 *
628 * @returns VBox status code.
629 * @param pNode Which node to search for pszName in.
630 * @param pszName Name of a byte string value.
631 * @param pvData Where to store the binary data.
632 * @param cbData Size of buffer pvData points too.
633 */
634CFGMR3DECL(int) CFGMR3QueryBytes(PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)
635{
636 PCFGMLEAF pLeaf;
637 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
638 if (VBOX_SUCCESS(rc))
639 {
640 if (pLeaf->enmType == CFGMVALUETYPE_BYTES)
641 {
642 if (cbData >= pLeaf->Value.Bytes.cb)
643 {
644 memcpy(pvData, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
645 memset((char *)pvData + pLeaf->Value.Bytes.cb, 0, cbData - pLeaf->Value.Bytes.cb);
646 }
647 else
648 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
649 }
650 else
651 rc = VERR_CFGM_NOT_BYTES;
652 }
653 return rc;
654}
655
656
657/**
658 * Creates the default configuration.
659 * This assumes an empty tree.
660 *
661 * @returns VBox status code.
662 * @param pVM VM handle.
663 */
664static int cfgmR3CreateDefault(PVM pVM)
665{
666 int rc;
667 int rcAll = VINF_SUCCESS;
668#define UPDATERC() do { if (VBOX_FAILURE(rc) && VBOX_SUCCESS(rcAll)) rcAll = rc; } while (0)
669
670 /*
671 * Root level.
672 */
673 PCFGMNODE pRoot = (PCFGMNODE)MMR3HeapAllocZ(pVM, MM_TAG_CFGM, sizeof(*pRoot));
674 if (!pRoot)
675 return VERR_NO_MEMORY;
676 pRoot->pVM = pVM;
677 pRoot->cchName = 0;
678
679 Assert(!pVM->cfgm.s.pRoot);
680 pVM->cfgm.s.pRoot = pRoot;
681
682 /*
683 * Create VM default values.
684 */
685 rc = CFGMR3InsertString(pRoot, "Name", "Default VM");
686 UPDATERC();
687 rc = CFGMR3InsertInteger(pRoot, "RamSize", 128 * _1M);
688 UPDATERC();
689 rc = CFGMR3InsertInteger(pRoot, "TimerMillies", 10);
690 UPDATERC();
691 rc = CFGMR3InsertInteger(pRoot, "RawR3Enabled", 1);
692 UPDATERC();
693 /** @todo CFGM Defaults: RawR0, PATMEnabled and CASMEnabled needs attention later. */
694 rc = CFGMR3InsertInteger(pRoot, "RawR0Enabled", 1);
695 UPDATERC();
696 rc = CFGMR3InsertInteger(pRoot, "PATMEnabled", 1);
697 UPDATERC();
698 rc = CFGMR3InsertInteger(pRoot, "CSAMEnabled", 1);
699 UPDATERC();
700
701 /*
702 * PDM.
703 */
704 PCFGMNODE pPdm;
705 rc = CFGMR3InsertNode(pRoot, "PDM", &pPdm);
706 UPDATERC();
707 PCFGMNODE pDevices = NULL;
708 rc = CFGMR3InsertNode(pPdm, "Devices", &pDevices);
709 UPDATERC();
710 rc = CFGMR3InsertInteger(pDevices, "LoadBuiltin", 1); /* boolean */
711 UPDATERC();
712 PCFGMNODE pDrivers = NULL;
713 rc = CFGMR3InsertNode(pPdm, "Drivers", &pDrivers);
714 UPDATERC();
715 rc = CFGMR3InsertInteger(pDrivers, "LoadBuiltin", 1); /* boolean */
716 UPDATERC();
717
718
719 /*
720 * Devices
721 */
722 pDevices = NULL;
723 rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices);
724 UPDATERC();
725 /* device */
726 PCFGMNODE pDev = NULL;
727 PCFGMNODE pInst = NULL;
728 PCFGMNODE pCfg = NULL;
729#if 0
730 PCFGMNODE pLunL0 = NULL;
731 PCFGMNODE pLunL1 = NULL;
732#endif
733
734 /*
735 * PC Arch.
736 */
737 rc = CFGMR3InsertNode(pDevices, "pcarch", &pDev);
738 UPDATERC();
739 rc = CFGMR3InsertNode(pDev, "0", &pInst);
740 UPDATERC();
741 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
742 UPDATERC();
743 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
744 UPDATERC();
745
746 /*
747 * PC Bios.
748 */
749 rc = CFGMR3InsertNode(pDevices, "pcbios", &pDev);
750 UPDATERC();
751 rc = CFGMR3InsertNode(pDev, "0", &pInst);
752 UPDATERC();
753 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
754 UPDATERC();
755 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
756 UPDATERC();
757 rc = CFGMR3InsertInteger(pCfg, "RamSize", 128 * _1M);
758 UPDATERC();
759 rc = CFGMR3InsertString(pCfg, "BootDevice0", "IDE");
760 UPDATERC();
761 rc = CFGMR3InsertString(pCfg, "BootDevice1", "NONE");
762 UPDATERC();
763 rc = CFGMR3InsertString(pCfg, "BootDevice2", "NONE");
764 UPDATERC();
765 rc = CFGMR3InsertString(pCfg, "BootDevice3", "NONE");
766 UPDATERC();
767 rc = CFGMR3InsertString(pCfg, "HardDiskDevice", "piix3ide");
768 UPDATERC();
769 rc = CFGMR3InsertString(pCfg, "FloppyDevice", "");
770 UPDATERC();
771 RTUUID Uuid;
772 RTUuidClear(&Uuid);
773 rc = CFGMR3InsertBytes(pCfg, "UUID", &Uuid, sizeof(Uuid));
774 UPDATERC();
775
776 /*
777 * PCI bus.
778 */
779 rc = CFGMR3InsertNode(pDevices, "pci", &pDev); /* piix3 */
780 UPDATERC();
781 rc = CFGMR3InsertNode(pDev, "0", &pInst);
782 UPDATERC();
783 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
784 UPDATERC();
785 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
786 UPDATERC();
787
788 /*
789 * PS/2 keyboard & mouse
790 */
791 rc = CFGMR3InsertNode(pDevices, "pckbd", &pDev);
792 UPDATERC();
793 rc = CFGMR3InsertNode(pDev, "0", &pInst);
794 UPDATERC();
795 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
796 UPDATERC();
797#if 0
798 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
799 UPDATERC();
800 rc = CFGMR3InsertString(pLunL0, "Driver", "KeyboardQueue");
801 UPDATERC();
802 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
803 UPDATERC();
804 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 64);
805 UPDATERC();
806 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
807 UPDATERC();
808 rc = CFGMR3InsertString(pLunL1, "Driver", "MainKeyboard");
809 UPDATERC();
810 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
811 UPDATERC();
812#endif
813#if 0
814 rc = CFGMR3InsertNode(pInst, "LUN#1", &pLunL0);
815 UPDATERC();
816 rc = CFGMR3InsertString(pLunL0, "Driver", "MouseQueue");
817 UPDATERC();
818 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
819 UPDATERC();
820 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 128);
821 UPDATERC();
822 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
823 UPDATERC();
824 rc = CFGMR3InsertString(pLunL1, "Driver", "MainMouse");
825 UPDATERC();
826 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
827 UPDATERC();
828#endif
829
830 /*
831 * i8254 Programmable Interval Timer And Dummy Speaker
832 */
833 rc = CFGMR3InsertNode(pDevices, "i8254", &pDev);
834 UPDATERC();
835 rc = CFGMR3InsertNode(pDev, "0", &pInst);
836 UPDATERC();
837#ifdef DEBUG
838 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
839 UPDATERC();
840#endif
841 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
842 UPDATERC();
843
844 /*
845 * i8259 Programmable Interrupt Controller.
846 */
847 rc = CFGMR3InsertNode(pDevices, "i8259", &pDev);
848 UPDATERC();
849 rc = CFGMR3InsertNode(pDev, "0", &pInst);
850 UPDATERC();
851 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
852 UPDATERC();
853 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
854 UPDATERC();
855
856 /*
857 * RTC MC146818.
858 */
859 rc = CFGMR3InsertNode(pDevices, "mc146818", &pDev);
860 UPDATERC();
861 rc = CFGMR3InsertNode(pDev, "0", &pInst);
862 UPDATERC();
863 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
864 UPDATERC();
865
866 /*
867 * VGA.
868 */
869 rc = CFGMR3InsertNode(pDevices, "vga", &pDev);
870 UPDATERC();
871 rc = CFGMR3InsertNode(pDev, "0", &pInst);
872 UPDATERC();
873 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
874 UPDATERC();
875 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
876 UPDATERC();
877 rc = CFGMR3InsertInteger(pCfg, "VRamSize", 4 * _1M);
878 UPDATERC();
879
880 /* Bios logo. */
881 rc = CFGMR3InsertInteger(pCfg, "FadeIn", 1);
882 UPDATERC();
883 rc = CFGMR3InsertInteger(pCfg, "FadeOut", 1);
884 UPDATERC();
885 rc = CFGMR3InsertInteger(pCfg, "LogoTime", 0);
886 UPDATERC();
887 rc = CFGMR3InsertString(pCfg, "LogoFile", "");
888 UPDATERC();
889
890#if 0
891 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
892 UPDATERC();
893 rc = CFGMR3InsertString(pLunL0, "Driver", "MainDisplay");
894 UPDATERC();
895#endif
896
897 /*
898 * IDE controller.
899 */
900 rc = CFGMR3InsertNode(pDevices, "piix3ide", &pDev); /* piix3 */
901 UPDATERC();
902 rc = CFGMR3InsertNode(pDev, "0", &pInst);
903 UPDATERC();
904 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
905 UPDATERC();
906 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
907 UPDATERC();
908
909
910
911 /*
912 * ...
913 */
914
915#undef UPDATERC
916 return rcAll;
917}
918
919
920
921
922/**
923 * Resolves a path reference to a child node.
924 *
925 * @returns VBox status code.
926 * @param pNode Which node to search for pszName in.
927 * @param pszPath Path to the child node.
928 * @param ppChild Where to store the pointer to the child node.
929 */
930static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild)
931{
932 if (pNode)
933 {
934 PCFGMNODE pChild = NULL;
935 for (;;)
936 {
937 /* skip leading slashes. */
938 while (*pszPath == '/')
939 pszPath++;
940
941 /* End of path? */
942 if (!*pszPath)
943 {
944 if (!pChild)
945 return VERR_CFGM_INVALID_CHILD_PATH;
946 *ppChild = pChild;
947 return VINF_SUCCESS;
948 }
949
950 /* find end of component. */
951 const char *pszNext = strchr(pszPath, '/');
952 if (!pszNext)
953 pszNext = strchr(pszPath, '\0');
954 RTUINT cchName = pszNext - pszPath;
955
956 /* search child list. */
957 pChild = pNode->pFirstChild;
958 for ( ; pChild; pChild = pChild->pNext)
959 if ( pChild->cchName == cchName
960 && !memcmp(pszPath, pChild->szName, cchName) )
961 break;
962
963 /* if not found, we're done. */
964 if (!pChild)
965 return VERR_CFGM_CHILD_NOT_FOUND;
966
967 /* next iteration */
968 pNode = pChild;
969 pszPath = pszNext;
970 }
971
972 /* won't get here */
973 }
974 else
975 return VERR_CFGM_NO_PARENT;
976}
977
978
979/**
980 * Resolves a path reference to a child node.
981 *
982 * @returns VBox status code.
983 * @param pNode Which node to search for pszName in.
984 * @param pszName Name of a byte string value.
985 * @param ppLeaf Where to store the pointer to the leaf node.
986 */
987static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
988{
989 int rc;
990 if (pNode)
991 {
992 RTUINT cchName = strlen(pszName);
993 PCFGMLEAF pLeaf = pNode->pFirstLeaf;
994 while (pLeaf)
995 {
996 if ( cchName == pLeaf->cchName
997 && !memcmp(pszName, pLeaf->szName, cchName) )
998 {
999 *ppLeaf = pLeaf;
1000 return VINF_SUCCESS;
1001 }
1002
1003 /* next */
1004 pLeaf = pLeaf->pNext;
1005 }
1006 rc = VERR_CFGM_VALUE_NOT_FOUND;
1007 }
1008 else
1009 rc = VERR_CFGM_NO_PARENT;
1010 return rc;
1011}
1012
1013
1014
1015/**
1016 * Creates a CFGM tree.
1017 *
1018 * This is intended for creating device/driver configs can be
1019 * passed around and later attached to the main tree in the
1020 * correct location.
1021 *
1022 * @returns Pointer to the root node.
1023 * @param pVM The VM handle.
1024 */
1025CFGMR3DECL(PCFGMNODE) CFGMR3CreateTree(PVM pVM)
1026{
1027 PCFGMNODE pNew = (PCFGMNODE)MMR3HeapAlloc(pVM, MM_TAG_CFGM, sizeof(*pNew));
1028 if (pNew)
1029 {
1030 pNew->pPrev = NULL;
1031 pNew->pNext = NULL;
1032 pNew->pParent = NULL;
1033 pNew->pFirstChild = NULL;
1034 pNew->pFirstLeaf = NULL;
1035 pNew->pVM = pVM;
1036 pNew->fRestrictedRoot = false;
1037 pNew->cchName = 0;
1038 pNew->szName[0] = 0;
1039 }
1040 return pNew;
1041}
1042
1043
1044/**
1045 * Insert subtree.
1046 *
1047 * This function inserts (no duplication) a tree created by CFGMR3CreateTree()
1048 * into the main tree.
1049 *
1050 * The root node of the inserted subtree will need to be reallocated, which
1051 * effectually means that the passed in pSubTree handle becomes invalid
1052 * upon successful return. Use the value returned in ppChild instead
1053 * of pSubTree.
1054 *
1055 * @returns VBox status code.
1056 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1057 * @param pNode Parent node.
1058 * @param pszName Name or path of the new child node.
1059 * @param pSubTree The subtree to insert. Must be returned by CFGMR3CreateTree().
1060 * @param ppChild Where to store the address of the new child node. (optional)
1061 */
1062CFGMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNODE pSubTree, PCFGMNODE *ppChild)
1063{
1064 /*
1065 * Validate input.
1066 */
1067 AssertPtrReturn(pSubTree, VERR_INVALID_POINTER);
1068 AssertReturn(!pSubTree->pParent, VERR_INVALID_PARAMETER);
1069 AssertReturn(pSubTree->pVM, VERR_INVALID_PARAMETER);
1070 AssertReturn(pSubTree->pParent != pSubTree->pVM->cfgm.s.pRoot, VERR_INVALID_PARAMETER);
1071 Assert(!pSubTree->pNext);
1072 Assert(!pSubTree->pPrev);
1073
1074 /*
1075 * Use CFGMR3InsertNode to create a new node and then
1076 * re-attach the children and leafs of the subtree to it.
1077 */
1078 PCFGMNODE pNewChild;
1079 int rc = CFGMR3InsertNode(pNode, pszName, &pNewChild);
1080 if (RT_SUCCESS(rc))
1081 {
1082 Assert(!pNewChild->pFirstChild);
1083 pNewChild->pFirstChild = pSubTree->pFirstChild;
1084 Assert(!pNewChild->pFirstLeaf);
1085 pNewChild->pFirstLeaf = pSubTree->pFirstLeaf;
1086 if (ppChild)
1087 *ppChild = pNewChild;
1088
1089 /* free the old subtree root */
1090 pSubTree->pVM = NULL;
1091 pSubTree->pFirstLeaf = NULL;
1092 pSubTree->pFirstChild = NULL;
1093 MMR3HeapFree(pSubTree);
1094 }
1095 return rc;
1096}
1097
1098
1099/**
1100 * Insert a node.
1101 *
1102 * @returns VBox status code.
1103 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1104 * @param pNode Parent node.
1105 * @param pszName Name or path of the new child node.
1106 * @param ppChild Where to store the address of the new child node. (optional)
1107 */
1108CFGMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild)
1109{
1110 int rc;
1111 if (pNode)
1112 {
1113 /*
1114 * If given a path we have to deal with it component by compontent.
1115 */
1116 while (*pszName == '/')
1117 pszName++;
1118 if (strchr(pszName, '/'))
1119 {
1120 char *pszDup = RTStrDup(pszName);
1121 if (pszDup)
1122 {
1123 char *psz = pszDup;
1124 for (;;)
1125 {
1126 /* Terminate at '/' and find the next component. */
1127 char *pszNext = strchr(psz, '/');
1128 if (pszNext)
1129 {
1130 *pszNext++ = '\0';
1131 while (*pszNext == '/')
1132 pszNext++;
1133 if (*pszNext == '\0')
1134 pszNext = NULL;
1135 }
1136
1137 /* does it exist? */
1138 PCFGMNODE pChild = CFGMR3GetChild(pNode, psz);
1139 if (!pChild)
1140 {
1141 /* no, insert it */
1142 rc = CFGMR3InsertNode(pNode, psz, &pChild);
1143 if (VBOX_FAILURE(rc))
1144 break;
1145 if (!pszNext)
1146 {
1147 if (ppChild)
1148 *ppChild = pChild;
1149 break;
1150 }
1151
1152 }
1153 /* if last component fail */
1154 else if (!pszNext)
1155 {
1156 rc = VERR_CFGM_NODE_EXISTS;
1157 break;
1158 }
1159
1160 /* next */
1161 pNode = pChild;
1162 psz = pszNext;
1163 }
1164 RTStrFree(pszDup);
1165 }
1166 else
1167 rc = VERR_NO_TMP_MEMORY;
1168 }
1169 /*
1170 * Not multicomponent, just make sure it's a non-zero name.
1171 */
1172 else if (*pszName)
1173 {
1174 /*
1175 * Check if already exists and find last node in chain.
1176 */
1177 size_t cchName = strlen(pszName);
1178 PCFGMNODE pPrev = pNode->pFirstChild;
1179 if (pPrev)
1180 {
1181 for (;; pPrev = pPrev->pNext)
1182 {
1183 if ( cchName == pPrev->cchName
1184 && !memcmp(pszName, pPrev->szName, cchName))
1185 return VERR_CFGM_NODE_EXISTS;
1186 if (!pPrev->pNext)
1187 break;
1188 }
1189 }
1190
1191 /*
1192 * Allocate and init node.
1193 */
1194 PCFGMNODE pNew = (PCFGMNODE)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1195 if (pNew)
1196 {
1197 pNew->pParent = pNode;
1198 pNew->pFirstChild = NULL;
1199 pNew->pFirstLeaf = NULL;
1200 pNew->pVM = pNode->pVM;
1201 pNew->fRestrictedRoot = false;
1202 pNew->cchName = cchName;
1203 memcpy(pNew->szName, pszName, cchName + 1);
1204
1205 /*
1206 * Insert into child list.
1207 */
1208 pNew->pNext = NULL;
1209 pNew->pPrev = pPrev;
1210 if (pPrev)
1211 pPrev->pNext = pNew;
1212 else
1213 pNode->pFirstChild = pNew;
1214 if (ppChild)
1215 *ppChild = pNew;
1216 rc = VINF_SUCCESS;
1217 }
1218 else
1219 rc = VERR_NO_MEMORY;
1220 }
1221 else
1222 {
1223 rc = VERR_CFGM_INVALID_NODE_PATH;
1224 AssertMsgFailed(("Invalid path %s\n", pszName));
1225 }
1226 }
1227 else
1228 {
1229 rc = VERR_CFGM_NO_PARENT;
1230 AssertMsgFailed(("No parent! path %s\n", pszName));
1231 }
1232
1233 return rc;
1234}
1235
1236
1237/**
1238 * Insert a node, format string name.
1239 *
1240 * @returns VBox status code.
1241 * @param pNode Parent node.
1242 * @param ppChild Where to store the address of the new child node. (optional)
1243 * @param pszNameFormat Name of or path the new child node.
1244 * @param ... Name format arguments.
1245 */
1246CFGMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
1247{
1248 va_list Args;
1249 va_start(Args, pszNameFormat);
1250 int rc = CFGMR3InsertNodeFV(pNode, ppChild, pszNameFormat, Args);
1251 va_end(Args);
1252 return rc;
1253}
1254
1255
1256/**
1257 * Insert a node, format string name.
1258 *
1259 * @returns VBox status code.
1260 * @param pNode Parent node.
1261 * @param ppChild Where to store the address of the new child node. (optional)
1262 * @param pszNameFormat Name or path of the new child node.
1263 * @param Args Name format arguments.
1264 */
1265CFGMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, va_list Args)
1266{
1267 int rc;
1268 char *pszName;
1269 RTStrAPrintfV(&pszName, pszNameFormat, Args);
1270 if (pszName)
1271 {
1272 rc = CFGMR3InsertNode(pNode, pszName, ppChild);
1273 RTStrFree(pszName);
1274 }
1275 else
1276 rc = VERR_NO_MEMORY;
1277 return rc;
1278}
1279
1280
1281/**
1282 * Marks the node as the root of a restricted subtree, i.e. the end of
1283 * a CFGMR3GetParent() journey.
1284 *
1285 * @param pNode The node to mark.
1286 */
1287CFGMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode)
1288{
1289 if (pNode)
1290 pNode->fRestrictedRoot = true;
1291}
1292
1293
1294/**
1295 * Insert a node.
1296 *
1297 * @returns VBox status code.
1298 * @param pNode Parent node.
1299 * @param pszName Name of the new child node.
1300 * @param ppLeaf Where to store the new leaf.
1301 * The caller must fill in the enmType and Value fields!
1302 */
1303static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1304{
1305 int rc;
1306 if (*pszName)
1307 {
1308 if (pNode)
1309 {
1310 /*
1311 * Check if already exists and find last node in chain.
1312 */
1313 size_t cchName = strlen(pszName);
1314 PCFGMLEAF pPrev = pNode->pFirstLeaf;
1315 if (pPrev)
1316 {
1317 for (;; pPrev = pPrev->pNext)
1318 {
1319 if ( cchName == pPrev->cchName
1320 && !memcmp(pszName, pPrev->szName, cchName))
1321 return VERR_CFGM_LEAF_EXISTS;
1322 if (!pPrev->pNext)
1323 break;
1324 }
1325 }
1326
1327 /*
1328 * Allocate and init node.
1329 */
1330 PCFGMLEAF pNew = (PCFGMLEAF)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1331 if (pNew)
1332 {
1333 pNew->cchName = cchName;
1334 memcpy(pNew->szName, pszName, cchName + 1);
1335
1336 /*
1337 * Insert into child list.
1338 */
1339 pNew->pNext = NULL;
1340 pNew->pPrev = pPrev;
1341 if (pPrev)
1342 pPrev->pNext = pNew;
1343 else
1344 pNode->pFirstLeaf = pNew;
1345 *ppLeaf = pNew;
1346 rc = VINF_SUCCESS;
1347 }
1348 else
1349 rc = VERR_NO_MEMORY;
1350 }
1351 else
1352 rc = VERR_CFGM_NO_PARENT;
1353 }
1354 else
1355 rc = VERR_CFGM_INVALID_CHILD_PATH;
1356 return rc;
1357}
1358
1359
1360/**
1361 * Remove a node.
1362 *
1363 * @param pNode Parent node.
1364 */
1365CFGMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode)
1366{
1367 if (pNode)
1368 {
1369 /*
1370 * Free children.
1371 */
1372 while (pNode->pFirstChild)
1373 CFGMR3RemoveNode(pNode->pFirstChild);
1374
1375 /*
1376 * Free leafs.
1377 */
1378 while (pNode->pFirstLeaf)
1379 cfgmR3RemoveLeaf(pNode, pNode->pFirstLeaf);
1380
1381 /*
1382 * Unlink ourselves.
1383 */
1384 if (pNode->pPrev)
1385 pNode->pPrev->pNext = pNode->pNext;
1386 else
1387 {
1388 if (pNode->pParent)
1389 pNode->pParent->pFirstChild = pNode->pNext;
1390 else if (pNode == pNode->pVM->cfgm.s.pRoot) /* might be a different tree */
1391 pNode->pVM->cfgm.s.pRoot = NULL;
1392 }
1393 if (pNode->pNext)
1394 pNode->pNext->pPrev = pNode->pPrev;
1395
1396 /*
1397 * Free ourselves. (bit of paranoia first)
1398 */
1399 pNode->pVM = NULL;
1400 pNode->pNext = NULL;
1401 pNode->pPrev = NULL;
1402 pNode->pParent = NULL;
1403 MMR3HeapFree(pNode);
1404 }
1405}
1406
1407
1408/**
1409 * Removes a leaf.
1410 *
1411 * @param pNode Parent node.
1412 * @param pLeaf Leaf to remove.
1413 */
1414static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf)
1415{
1416 if (pNode && pLeaf)
1417 {
1418 /*
1419 * Unlink.
1420 */
1421 if (pLeaf->pPrev)
1422 pLeaf->pPrev->pNext = pLeaf->pNext;
1423 else
1424 pNode->pFirstLeaf = pLeaf->pNext;
1425 if (pLeaf->pNext)
1426 pLeaf->pNext->pPrev = pLeaf->pPrev;
1427
1428 /*
1429 * Free value and node.
1430 */
1431 cfgmR3FreeValue(pLeaf);
1432 pLeaf->pNext = NULL;
1433 pLeaf->pPrev = NULL;
1434 MMR3HeapFree(pLeaf);
1435 }
1436}
1437
1438
1439/**
1440 * Frees whatever resources the leaf value is owning.
1441 *
1442 * Use this before assigning a new value to a leaf.
1443 * The caller must either free the leaf or assign a new value to it.
1444 *
1445 * @param pLeaf Pointer to the leaf which value should be free.
1446 */
1447static void cfgmR3FreeValue(PCFGMLEAF pLeaf)
1448{
1449 if (pLeaf)
1450 {
1451 switch (pLeaf->enmType)
1452 {
1453 case CFGMVALUETYPE_BYTES:
1454 MMR3HeapFree(pLeaf->Value.Bytes.pau8);
1455 pLeaf->Value.Bytes.pau8 = NULL;
1456 pLeaf->Value.Bytes.cb = 0;
1457 break;
1458
1459 case CFGMVALUETYPE_STRING:
1460 MMR3HeapFree(pLeaf->Value.String.psz);
1461 pLeaf->Value.String.psz = NULL;
1462 pLeaf->Value.String.cch = 0;
1463 break;
1464
1465 case CFGMVALUETYPE_INTEGER:
1466 break;
1467 }
1468 pLeaf->enmType = (CFGMVALUETYPE)0;
1469 }
1470}
1471
1472
1473/**
1474 * Inserts a new integer value.
1475 *
1476 * @returns VBox status code.
1477 * @param pNode Parent node.
1478 * @param pszName Value name.
1479 * @param u64Integer The value.
1480 */
1481CFGMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer)
1482{
1483 PCFGMLEAF pLeaf;
1484 int rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1485 if (VBOX_SUCCESS(rc))
1486 {
1487 pLeaf->enmType = CFGMVALUETYPE_INTEGER;
1488 pLeaf->Value.Integer.u64 = u64Integer;
1489 }
1490 return rc;
1491}
1492
1493
1494/**
1495 * Inserts a new string value.
1496 *
1497 * @returns VBox status code.
1498 * @param pNode Parent node.
1499 * @param pszName Value name.
1500 * @param pszString The value.
1501 */
1502CFGMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
1503{
1504 int rc;
1505 if (pNode)
1506 {
1507 /*
1508 * Allocate string object first.
1509 */
1510 size_t cchString = strlen(pszString) + 1;
1511 char *pszStringCopy = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, RT_ALIGN_Z(cchString, 16));
1512 if (pszStringCopy)
1513 {
1514 memcpy(pszStringCopy, pszString, cchString);
1515
1516 /*
1517 * Create value leaf and set it to string type.
1518 */
1519 PCFGMLEAF pLeaf;
1520 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1521 if (VBOX_SUCCESS(rc))
1522 {
1523 pLeaf->enmType = CFGMVALUETYPE_STRING;
1524 pLeaf->Value.String.psz = pszStringCopy;
1525 pLeaf->Value.String.cch = cchString;
1526 }
1527 }
1528 else
1529 rc = VERR_NO_MEMORY;
1530 }
1531 else
1532 rc = VERR_CFGM_NO_PARENT;
1533
1534 return rc;
1535}
1536
1537
1538
1539/**
1540 * Inserts a new integer value.
1541 *
1542 * @returns VBox status code.
1543 * @param pNode Parent node.
1544 * @param pszName Value name.
1545 * @param pvBytes The value.
1546 * @param cbBytes The value size.
1547 */
1548CFGMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes)
1549{
1550 int rc;
1551 if (pNode)
1552 {
1553 if (cbBytes == (RTUINT)cbBytes)
1554 {
1555 /*
1556 * Allocate string object first.
1557 */
1558 void *pvCopy = MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, RT_ALIGN_Z(cbBytes, 16));
1559 if (pvCopy || !cbBytes)
1560 {
1561 memcpy(pvCopy, pvBytes, cbBytes);
1562
1563 /*
1564 * Create value leaf and set it to string type.
1565 */
1566 PCFGMLEAF pLeaf;
1567 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1568 if (VBOX_SUCCESS(rc))
1569 {
1570 pLeaf->enmType = CFGMVALUETYPE_BYTES;
1571 pLeaf->Value.Bytes.cb = cbBytes;
1572 pLeaf->Value.Bytes.pau8 = (uint8_t *)pvCopy;
1573 }
1574 }
1575 else
1576 rc = VERR_NO_MEMORY;
1577 }
1578 else
1579 rc = VERR_OUT_OF_RANGE;
1580 }
1581 else
1582 rc = VERR_CFGM_NO_PARENT;
1583
1584 return rc;
1585}
1586
1587
1588/**
1589 * Remove a value.
1590 *
1591 * @returns VBox status code.
1592 * @param pNode Parent node.
1593 * @param pszName Name of the new child node.
1594 */
1595CFGMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName)
1596{
1597 PCFGMLEAF pLeaf;
1598 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
1599 if (VBOX_SUCCESS(rc))
1600 cfgmR3RemoveLeaf(pNode, pLeaf);
1601 return rc;
1602}
1603
1604
1605
1606/*
1607 * -+- helper apis -+-
1608 */
1609
1610
1611/**
1612 * Query unsigned 64-bit integer value.
1613 *
1614 * @returns VBox status code.
1615 * @param pNode Which node to search for pszName in.
1616 * @param pszName Name of an integer value.
1617 * @param pu64 Where to store the integer value.
1618 */
1619CFGMR3DECL(int) CFGMR3QueryU64(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
1620{
1621 return CFGMR3QueryInteger(pNode, pszName, pu64);
1622}
1623
1624
1625/**
1626 * Query signed 64-bit integer value.
1627 *
1628 * @returns VBox status code.
1629 * @param pNode Which node to search for pszName in.
1630 * @param pszName Name of an integer value.
1631 * @param pi64 Where to store the value.
1632 */
1633CFGMR3DECL(int) CFGMR3QueryS64(PCFGMNODE pNode, const char *pszName, int64_t *pi64)
1634{
1635 uint64_t u64;
1636 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1637 if (VBOX_SUCCESS(rc))
1638 *pi64 = (int64_t)u64;
1639 return rc;
1640}
1641
1642
1643/**
1644 * Query unsigned 32-bit integer value.
1645 *
1646 * @returns VBox status code.
1647 * @param pNode Which node to search for pszName in.
1648 * @param pszName Name of an integer value.
1649 * @param pu32 Where to store the value.
1650 */
1651CFGMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
1652{
1653 uint64_t u64;
1654 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1655 if (VBOX_SUCCESS(rc))
1656 {
1657 if (!(u64 & 0xffffffff00000000ULL))
1658 *pu32 = (uint32_t)u64;
1659 else
1660 rc = VERR_CFGM_INTEGER_TOO_BIG;
1661 }
1662 return rc;
1663}
1664
1665
1666/**
1667 * Query signed 32-bit integer value.
1668 *
1669 * @returns VBox status code.
1670 * @param pNode Which node to search for pszName in.
1671 * @param pszName Name of an integer value.
1672 * @param pi32 Where to store the value.
1673 */
1674CFGMR3DECL(int) CFGMR3QueryS32(PCFGMNODE pNode, const char *pszName, int32_t *pi32)
1675{
1676 uint64_t u64;
1677 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1678 if (VBOX_SUCCESS(rc))
1679 {
1680 if ( !(u64 & 0xffffffff80000000ULL)
1681 || (u64 & 0xffffffff80000000ULL) == 0xffffffff80000000ULL)
1682 *pi32 = (int32_t)u64;
1683 else
1684 rc = VERR_CFGM_INTEGER_TOO_BIG;
1685 }
1686 return rc;
1687}
1688
1689
1690/**
1691 * Query unsigned 16-bit integer value.
1692 *
1693 * @returns VBox status code.
1694 * @param pNode Which node to search for pszName in.
1695 * @param pszName Name of an integer value.
1696 * @param pu16 Where to store the value.
1697 */
1698CFGMR3DECL(int) CFGMR3QueryU16(PCFGMNODE pNode, const char *pszName, uint16_t *pu16)
1699{
1700 uint64_t u64;
1701 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1702 if (VBOX_SUCCESS(rc))
1703 {
1704 if (!(u64 & 0xffffffffffff0000ULL))
1705 *pu16 = (int16_t)u64;
1706 else
1707 rc = VERR_CFGM_INTEGER_TOO_BIG;
1708 }
1709 return rc;
1710}
1711
1712
1713/**
1714 * Query signed 16-bit integer value.
1715 *
1716 * @returns VBox status code.
1717 * @param pNode Which node to search for pszName in.
1718 * @param pszName Name of an integer value.
1719 * @param pi16 Where to store the value.
1720 */
1721CFGMR3DECL(int) CFGMR3QueryS16(PCFGMNODE pNode, const char *pszName, int16_t *pi16)
1722{
1723 uint64_t u64;
1724 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1725 if (VBOX_SUCCESS(rc))
1726 {
1727 if ( !(u64 & 0xffffffffffff8000ULL)
1728 || (u64 & 0xffffffffffff8000ULL) == 0xffffffffffff8000ULL)
1729 *pi16 = (int16_t)u64;
1730 else
1731 rc = VERR_CFGM_INTEGER_TOO_BIG;
1732 }
1733 return rc;
1734}
1735
1736
1737/**
1738 * Query unsigned 8-bit integer value.
1739 *
1740 * @returns VBox status code.
1741 * @param pNode Which node to search for pszName in.
1742 * @param pszName Name of an integer value.
1743 * @param pu8 Where to store the value.
1744 */
1745CFGMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
1746{
1747 uint64_t u64;
1748 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1749 if (VBOX_SUCCESS(rc))
1750 {
1751 if (!(u64 & 0xffffffffffffff00ULL))
1752 *pu8 = (uint8_t)u64;
1753 else
1754 rc = VERR_CFGM_INTEGER_TOO_BIG;
1755 }
1756 return rc;
1757}
1758
1759
1760/**
1761 * Query signed 8-bit integer value.
1762 *
1763 * @returns VBox status code.
1764 * @param pNode Which node to search for pszName in.
1765 * @param pszName Name of an integer value.
1766 * @param pi8 Where to store the value.
1767 */
1768CFGMR3DECL(int) CFGMR3QueryS8(PCFGMNODE pNode, const char *pszName, int8_t *pi8)
1769{
1770 uint64_t u64;
1771 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1772 if (VBOX_SUCCESS(rc))
1773 {
1774 if ( !(u64 & 0xffffffffffffff80ULL)
1775 || (u64 & 0xffffffffffffff80ULL) == 0xffffffffffffff80ULL)
1776 *pi8 = (int8_t)u64;
1777 else
1778 rc = VERR_CFGM_INTEGER_TOO_BIG;
1779 }
1780 return rc;
1781}
1782
1783
1784/**
1785 * Query boolean integer value.
1786 *
1787 * @returns VBox status code.
1788 * @param pNode Which node to search for pszName in.
1789 * @param pszName Name of an integer value.
1790 * @param pf Where to store the value.
1791 * @remark This function will interpret any non-zero value as true.
1792 */
1793CFGMR3DECL(int) CFGMR3QueryBool(PCFGMNODE pNode, const char *pszName, bool *pf)
1794{
1795 uint64_t u64;
1796 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1797 if (VBOX_SUCCESS(rc))
1798 *pf = u64 ? true : false;
1799 return rc;
1800}
1801
1802
1803/**
1804 * Query pointer integer value.
1805 *
1806 * @returns VBox status code.
1807 * @param pNode Which node to search for pszName in.
1808 * @param pszName Name of an integer value.
1809 * @param ppv Where to store the value.
1810 */
1811CFGMR3DECL(int) CFGMR3QueryPtr(PCFGMNODE pNode, const char *pszName, void **ppv)
1812{
1813 uint64_t u64;
1814 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1815 if (VBOX_SUCCESS(rc))
1816 {
1817 uintptr_t u = (uintptr_t)u64;
1818 if (u64 == u)
1819 *ppv = (void *)u;
1820 else
1821 rc = VERR_CFGM_INTEGER_TOO_BIG;
1822 }
1823 return rc;
1824}
1825
1826
1827/**
1828 * Query Guest Context pointer integer value.
1829 *
1830 * @returns VBox status code.
1831 * @param pNode Which node to search for pszName in.
1832 * @param pszName Name of an integer value.
1833 * @param pGCPtr Where to store the value.
1834 */
1835CFGMR3DECL(int) CFGMR3QueryGCPtr(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)
1836{
1837 uint64_t u64;
1838 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1839 if (VBOX_SUCCESS(rc))
1840 {
1841 RTGCPTR u = (RTGCPTR)u64;
1842 if (u64 == u)
1843 *pGCPtr = u;
1844 else
1845 rc = VERR_CFGM_INTEGER_TOO_BIG;
1846 }
1847 return rc;
1848}
1849
1850
1851/**
1852 * Query Guest Context unsigned pointer value.
1853 *
1854 * @returns VBox status code.
1855 * @param pNode Which node to search for pszName in.
1856 * @param pszName Name of an integer value.
1857 * @param pGCPtr Where to store the value.
1858 */
1859CFGMR3DECL(int) CFGMR3QueryGCPtrU(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)
1860{
1861 uint64_t u64;
1862 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1863 if (VBOX_SUCCESS(rc))
1864 {
1865 RTGCUINTPTR u = (RTGCUINTPTR)u64;
1866 if (u64 == u)
1867 *pGCPtr = u;
1868 else
1869 rc = VERR_CFGM_INTEGER_TOO_BIG;
1870 }
1871 return rc;
1872}
1873
1874
1875/**
1876 * Query Guest Context signed pointer value.
1877 *
1878 * @returns VBox status code.
1879 * @param pNode Which node to search for pszName in.
1880 * @param pszName Name of an integer value.
1881 * @param pGCPtr Where to store the value.
1882 */
1883CFGMR3DECL(int) CFGMR3QueryGCPtrS(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)
1884{
1885 uint64_t u64;
1886 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1887 if (VBOX_SUCCESS(rc))
1888 {
1889 RTGCINTPTR u = (RTGCINTPTR)u64;
1890 if (u64 == (uint64_t)u)
1891 *pGCPtr = u;
1892 else
1893 rc = VERR_CFGM_INTEGER_TOO_BIG;
1894 }
1895 return rc;
1896}
1897
1898
1899/**
1900 * Query zero terminated character value storing it in a
1901 * buffer allocated from the MM heap.
1902 *
1903 * @returns VBox status code.
1904 * @param pNode Which node to search for pszName in.
1905 * @param pszName Value name. This value must be of zero terminated character string type.
1906 * @param ppszString Where to store the string pointer.
1907 * Free this using MMR3HeapFree().
1908 */
1909CFGMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
1910{
1911 size_t cch;
1912 int rc = CFGMR3QuerySize(pNode, pszName, &cch);
1913 if (VBOX_SUCCESS(rc))
1914 {
1915 char *pszString = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_USER, cch);
1916 if (pszString)
1917 {
1918 rc = CFGMR3QueryString(pNode, pszName, pszString, cch);
1919 if (VBOX_SUCCESS(rc))
1920 *ppszString = pszString;
1921 else
1922 MMR3HeapFree(pszString);
1923 }
1924 else
1925 rc = VERR_NO_MEMORY;
1926 }
1927 return rc;
1928}
1929
1930
1931
1932/**
1933 * Dumps the configuration (sub)tree to the release log.
1934 *
1935 * @param pRoot The root node of the dump.
1936 */
1937CFGMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot)
1938{
1939 LogRel(("************************* CFGM dump *************************\n"));
1940 cfgmR3Info(pRoot->pVM, DBGFR3InfoLogRelHlp(), NULL);
1941 LogRel(("********************* End of CFGM dump **********************\n"));
1942}
1943
1944
1945/**
1946 * Info handler, internal version.
1947 *
1948 * @param pVM The VM handle.
1949 * @param pHlp Callback functions for doing output.
1950 * @param pszArgs Argument string. Optional and specific to the handler.
1951 */
1952static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1953{
1954 /*
1955 * Figure where to start.
1956 */
1957 PCFGMNODE pRoot = pVM->cfgm.s.pRoot;
1958 if (pszArgs && *pszArgs)
1959 {
1960 int rc = cfgmR3ResolveNode(pRoot, pszArgs, &pRoot);
1961 if (VBOX_FAILURE(rc))
1962 {
1963 pHlp->pfnPrintf(pHlp, "Failed to resolve CFGM path '%s', %Vrc", pszArgs, rc);
1964 return;
1965 }
1966 }
1967
1968 /*
1969 * Dump the specified tree.
1970 */
1971 pHlp->pfnPrintf(pHlp, "pRoot=%p:{", pRoot);
1972 cfgmR3DumpPath(pRoot, pHlp);
1973 pHlp->pfnPrintf(pHlp, "}\n");
1974 cfgmR3Dump(pRoot, 0, pHlp);
1975}
1976
1977
1978/**
1979 * Recursivly prints a path name.
1980 */
1981static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp)
1982{
1983 if (pNode->pParent)
1984 cfgmR3DumpPath(pNode->pParent, pHlp);
1985 pHlp->pfnPrintf(pHlp, "%s/", pNode->szName);
1986}
1987
1988
1989/**
1990 * Dumps a branch of a tree.
1991 */
1992static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp)
1993{
1994 /*
1995 * Path.
1996 */
1997 pHlp->pfnPrintf(pHlp, "[");
1998 cfgmR3DumpPath(pRoot, pHlp);
1999 pHlp->pfnPrintf(pHlp, "] (level %d)%s\n", iLevel, pRoot->fRestrictedRoot ? " (restricted root)" : "");
2000
2001 /*
2002 * Values.
2003 */
2004 PCFGMLEAF pLeaf;
2005 unsigned cchMax = 0;
2006 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
2007 cchMax = RT_MAX(cchMax, pLeaf->cchName);
2008 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
2009 {
2010 switch (CFGMR3GetValueType(pLeaf))
2011 {
2012 case CFGMVALUETYPE_INTEGER:
2013 pHlp->pfnPrintf(pHlp, " %-*s <integer> = %#018llx (%lld)\n", cchMax, pLeaf->szName, pLeaf->Value.Integer.u64, pLeaf->Value.Integer.u64);
2014 break;
2015
2016 case CFGMVALUETYPE_STRING:
2017 pHlp->pfnPrintf(pHlp, " %-*s <string> = \"%s\" (cch=%d)\n", cchMax, pLeaf->szName, pLeaf->Value.String.psz, pLeaf->Value.String.cch);
2018 break;
2019
2020 case CFGMVALUETYPE_BYTES:
2021 pHlp->pfnPrintf(pHlp, " %-*s <bytes> = \"%.*Vhxs\" (cb=%d)\n", cchMax, pLeaf->szName, pLeaf->Value.Bytes.cb, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
2022 break;
2023
2024 default:
2025 AssertMsgFailed(("bad leaf!\n"));
2026 break;
2027 }
2028 }
2029 pHlp->pfnPrintf(pHlp, "\n");
2030
2031 /*
2032 * Children.
2033 */
2034 for (PCFGMNODE pChild = CFGMR3GetFirstChild(pRoot); pChild; pChild = CFGMR3GetNextChild(pChild))
2035 {
2036 Assert(pChild->pNext != pChild);
2037 Assert(pChild->pPrev != pChild);
2038 Assert(pChild->pPrev != pChild->pNext || !pChild->pPrev);
2039 Assert(pChild->pFirstChild != pChild);
2040 Assert(pChild->pParent != pChild);
2041 cfgmR3Dump(pChild, iLevel + 1, pHlp);
2042 }
2043}
2044
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette