VirtualBox

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

Last change on this file since 19 was 1, checked in by vboxsync, 55 years ago

import

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