blob: 8881fdf06cf7dc08d515c54f23a98a231f661893 [file] [log] [blame]
Patrick Williamsed173c32021-10-06 13:09:19 -05001#pragma once
2
3#include "tinyxml2.h"
4
5#include <phosphor-logging/elog-errors.hpp>
6#include <phosphor-logging/log.hpp>
Jason M. Bills0748c692022-09-08 15:34:08 -07007#include <types.hpp>
Patrick Williamsed173c32021-10-06 13:09:19 -05008
9#include <map>
10#include <sstream>
11#include <stack>
12#include <string>
13#include <variant>
14#include <vector>
15
16namespace bios
17{
18/* Can hold one 'option'
19 * For example
20 * <option text="TIS" value="0x0"/>
21 */
Arun Lal K M7a8ab9e2023-05-03 12:19:22 +000022using OptionType = std::tuple<std::string, ipmi::DbusVariant, std::string>;
Patrick Williamsed173c32021-10-06 13:09:19 -050023
24/* Can hold one 'options'
25 * For example
26 * <options>
27 * <option text="TIS" value="0x0"/>
28 * <option text="PTP FIFO" value="0x1"/>
29 * <option text="PTP CRB" value="0x2"/>
30 * </options>
31 */
32using OptionTypeVector = std::vector<OptionType>;
33
34/* Can hold one 'knob'
35 * For example
36 * <knob type="scalar" setupType="oneof" name="TpmDeviceInterfaceAttempt"
37 * varstoreIndex="14" prompt="Attempt PTP TPM Device Interface"
38 * description="Attempt PTP TPM Device Interface: PTP FIFO, PTP CRB" size="1"
39 * offset="0x0005" depex="Sif( _LIST_ TpmDevice _EQU_ 0 1 ) _AND_ Sif(
40 * TpmDeviceInterfacePtpFifoSupported _EQU_ 0 OR
41 * TpmDeviceInterfacePtpCrbSupported _EQU_ 0 )" default="0x00"
42 *CurrentVal="0x00"> <options> <option text="TIS" value="0x0"/> <option
43 *text="PTP FIFO" value="0x1"/> <option text="PTP CRB" value="0x2"/>
44 * </options>
45 * </knob>
46 */
47using BiosBaseTableTypeEntry =
48 std::tuple<std::string, bool, std::string, std::string, std::string,
Jason M. Bills0748c692022-09-08 15:34:08 -070049 ipmi::DbusVariant, ipmi::DbusVariant, OptionTypeVector>;
Patrick Williamsed173c32021-10-06 13:09:19 -050050
51/* Can hold one 'biosknobs'
52 * biosknobs has array of 'knob' */
53using BiosBaseTableType = std::map<std::string, BiosBaseTableTypeEntry>;
54
55namespace knob
56{
57/* These are the operators we support in a 'depex' expression
58 * Note: We also support '_LIST_', 'Sif', 'Gif', 'Dif', and 'NOT'. But they are
59 * handeled sepeartely. */
60enum class DepexOperators
61{
62 unknown = 0,
63 OR,
64 AND,
65 GT,
66 GTE,
67 LTE,
68 LT,
69 EQU,
70 NEQ,
71 MODULO
72};
73
74namespace option
75{
76/* Can hold one 'option' */
77struct option
78{
79 option(std::string text, std::string value) :
80 text(std::move(text)), value(std::move(value))
81 {}
82
83 std::string text;
84 std::string value;
85};
86} // namespace option
87
88/* Can hold one 'knob' */
89struct knob
90{
91 knob(std::string nameStr, std::string currentValStr, int currentVal,
92 std::string descriptionStr, std::string defaultStr,
93 std::string promptStr, std::string depexStr,
94 std::string& setupTypeStr) :
Vernon Mauerydcff1502022-09-28 11:12:46 -070095 depex(false),
96 readOnly(("ReadOnly" == setupTypeStr) ? true : false),
97 currentVal(currentVal), nameStr(std::move(nameStr)),
98 currentValStr(std::move(currentValStr)),
Patrick Williamsed173c32021-10-06 13:09:19 -050099 descriptionStr(std::move(descriptionStr)),
100 defaultStr(std::move(defaultStr)), promptStr(std::move(promptStr)),
Vernon Mauerydcff1502022-09-28 11:12:46 -0700101 depexStr(std::move(depexStr))
Patrick Williamsed173c32021-10-06 13:09:19 -0500102 {}
103
104 bool depex;
105 bool readOnly;
106 int currentVal;
107
108 std::string nameStr;
109 std::string currentValStr;
110 std::string descriptionStr;
111 std::string defaultStr;
112 std::string promptStr;
113 std::string depexStr;
114
115 /* Can hold one 'options' */
116 std::vector<option::option> options;
117};
118} // namespace knob
119
120/* Class capable of computing 'depex' expression. */
121class Depex
122{
123 public:
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500124 Depex(std::vector<knob::knob>& knobs) : mKnobs(knobs) {}
Patrick Williamsed173c32021-10-06 13:09:19 -0500125
126 /* Compute 'depex' expression of all knobs in 'biosknobs'. */
127 void compute()
128 {
129 mError.clear();
130
131 for (auto& knob : mKnobs)
132 {
133 /* if 'depex' == "TRUE" no need to execute expression. */
134 if ("TRUE" == knob.depexStr)
135 {
136 knob.depex = true;
137 }
138 else if (!knob.readOnly)
139 {
140 int value = 0;
141
142 if (!evaluateExpression(knob.depexStr, value))
143 {
144 mError.emplace_back("bad depex: " + knob.depexStr +
145 " in knob: " + knob.nameStr);
146 }
147 else
148 {
149 if (value)
150 {
151 knob.depex = true;
152 }
153 }
154 }
155 }
156 }
157
158 /* Returns the number of 'knob's which have a bad 'depex' expression. */
159 size_t getErrorCount()
160 {
161 return mError.size();
162 }
163
164 /* Prints all the 'knob's which have a bad 'depex' expression. */
165 void printError()
166 {
167 for (auto& error : mError)
168 {
169 phosphor::logging::log<phosphor::logging::level::ERR>(
170 error.c_str());
171 }
172 }
173
174 private:
175 /* Returns 'true' if the argument string is a number. */
176 bool isNumber(const std::string& s)
177 {
178 return !s.empty() &&
179 std::find_if(s.begin(), s.end(), [](unsigned char c) {
Patrick Williams87381412023-10-20 11:18:48 -0500180 return !std::isdigit(c);
181 }) == s.end();
Patrick Williamsed173c32021-10-06 13:09:19 -0500182 }
183
184 /* Returns 'true' if the argument string is hex representation of a number.
185 */
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500186 bool isHexNotation(const std::string& s)
Patrick Williamsed173c32021-10-06 13:09:19 -0500187 {
188 return s.compare(0, 2, "0x") == 0 && s.size() > 2 &&
189 s.find_first_not_of("0123456789abcdefABCDEF", 2) ==
190 std::string::npos;
191 }
192
193 /* Function to find current value of a 'knob'
194 * search is done using 'knob' attribute 'name' */
195 bool getValue(std::string& variableName, int& value)
196 {
197 for (auto& knob : mKnobs)
198 {
199 if (knob.nameStr == variableName)
200 {
201 value = knob.currentVal;
202 return true;
203 }
204 }
205
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500206 std::string error = "Unable to find knob: " + variableName +
207 " in knob list\n";
Patrick Williamsed173c32021-10-06 13:09:19 -0500208 phosphor::logging::log<phosphor::logging::level::ERR>(error.c_str());
209
210 return false;
211 }
212
213 /* Get the expression enclosed within brackets, i.e., between '(' and ')' */
214 bool getSubExpression(const std::string& expression,
215 std::string& subExpression, size_t& i)
216 {
217 int level = 1;
218 subExpression.clear();
219
220 for (; i < expression.length(); i++)
221 {
222 if (expression[i] == '(')
223 {
224 ++level;
225 }
226 else if (expression[i] == ')')
227 {
228 --level;
229 if (level == 0)
230 {
231 break;
232 }
233 }
234
235 subExpression.push_back(expression[i]);
236 }
237
238 if (!subExpression.empty())
239 {
240 return true;
241 }
242
243 return false;
244 }
245
246 /* Function to handle operator '_LIST_'
247 * Convert a '_LIST_' expression to a normal expression
248 * Example "_LIST_ VariableA _EQU_ 0 1" is converted to "VariableA _EQU_ 0
249 * OR VariableA _EQU_ 1" */
250 bool getListExpression(const std::string& expression,
251 std::string& subExpression, size_t& i)
252 {
253 subExpression.clear();
254
255 int cnt = 0;
256 std::string variableStr;
257 std::string operatorStr;
258
259 for (; i < expression.length(); i++)
260 {
261 if (expression[i] == '(')
262 {
263 return false;
264 }
265 else if (expression[i] == ')')
266 {
267 break;
268 }
269 else if (expression[i] == ' ')
270 {
271 /* whitespace */
272 continue;
273 }
274 else
275 {
276 std::string word;
277
278 /* Get the next word in expression string */
279 while ((i < expression.length()) && (expression[i] != ' '))
280 {
281 word.push_back(expression[i++]);
282 }
283
284 if (word == "_OR_" || word == "OR" || word == "_AND_" ||
285 word == "AND" || word == "NOT")
286 {
287 i = i - word.length();
288 break;
289 }
290
291 ++cnt;
292
293 if (cnt == 1)
294 {
295 variableStr = word;
296 }
297 else if (cnt == 2)
298 {
299 operatorStr = word;
300 }
301 else
302 {
303 if (cnt > 3)
304 {
Jatkiewicz, Joanna16bbc6b2023-11-27 10:23:29 +0100305 if (operatorStr == "_EQU_" || operatorStr == "EQU")
306 {
307 subExpression += " OR ";
308 }
309 if (operatorStr == "_NEQ_" || operatorStr == "NEQ")
310 {
311 subExpression += " AND ";
312 }
Patrick Williamsed173c32021-10-06 13:09:19 -0500313 }
314
315 subExpression += "( ";
316 subExpression += variableStr;
317 subExpression += " ";
318 subExpression += operatorStr;
319 subExpression += " ";
320 subExpression += word;
321 subExpression += " )";
322 }
323 }
324 }
325
326 if (!subExpression.empty())
327 {
328 return true;
329 }
330
331 return false;
332 }
333
334 /* Function to handle operator 'NOT'
335 * 1) Find the variable
336 * 2) apply NOT on the variable */
337 bool getNotValue(const std::string& expression, size_t& i, int& value)
338 {
339 std::string word;
340
341 for (; i < expression.length(); i++)
342 {
343 if (expression[i] == ' ')
344 {
345 /* whitespace */
346 continue;
347 }
348 else
349 {
350 /* Get the next word in expression string */
351 while ((i < expression.length()) && (expression[i] != ' '))
352 {
353 word.push_back(expression[i++]);
354 }
355
356 break;
357 }
358 }
359
360 if (!word.empty())
361 {
362 if (getValue(word, value))
363 {
364 value = !value;
365 return true;
366 }
367 }
368
369 return false;
370 }
371
372 /* 1) Pop one operator from operator stack, example 'OR'
373 * 2) Pop two variable from variable stack, example VarA and VarB
374 * 3) Push back result of 'VarA OR VarB' to variable stack
375 * 4) Repeat till operator stack is empty
376 *
377 * The last variable in variable stack is the output of the expression. */
378 bool evaluateExprStack(std::stack<int>& values,
379 std::stack<knob::DepexOperators>& operators,
380 int& output)
381 {
382 if (values.size() != (operators.size() + 1))
383 {
384 return false;
385 }
386
387 while (!operators.empty())
388 {
389 int b = values.top();
390 values.pop();
391
392 int a = values.top();
393 values.pop();
394
395 switch (operators.top())
396 {
397 case knob::DepexOperators::OR:
398 values.emplace(a | b);
399 break;
400
401 case knob::DepexOperators::AND:
402 values.emplace(a & b);
403 break;
404
405 case knob::DepexOperators::EQU:
406 if (a == b)
407 {
408 values.emplace(1);
409 break;
410 }
411
412 values.emplace(0);
413 break;
414
415 case knob::DepexOperators::NEQ:
416 if (a != b)
417 {
418 values.emplace(1);
419 break;
420 }
421
422 values.emplace(0);
423 break;
424
425 case knob::DepexOperators::LTE:
426 if (a <= b)
427 {
428 values.emplace(1);
429 break;
430 }
431
432 values.emplace(0);
433 break;
434
435 case knob::DepexOperators::LT:
436 if (a < b)
437 {
438 values.emplace(1);
439 break;
440 }
441
442 values.emplace(0);
443 break;
444
445 case knob::DepexOperators::GTE:
446 if (a >= b)
447 {
448 values.emplace(1);
449 break;
450 }
451
452 values.emplace(0);
453 break;
454
455 case knob::DepexOperators::GT:
456 if (a > b)
457 {
458 values.emplace(1);
459 break;
460 }
461
462 values.emplace(0);
463 break;
464
465 case knob::DepexOperators::MODULO:
466 if (b == 0)
467 {
468 return false;
469 }
470 values.emplace(a % b);
471 break;
472
473 default:
474 return false;
475 }
476
477 operators.pop();
478 }
479
480 if (values.size() == 1)
481 {
482 output = values.top();
483 values.pop();
484
485 return true;
486 }
487
488 return false;
489 }
490
491 /* Evaluvate one 'depex' expression
492 * 1) Find a word in expression string
493 * 2) If word is a variable push to variable stack
494 * 3) If word is a operator push to operator stack
495 *
496 * Execute the stack at end to get the result of expression. */
497 bool evaluateExpression(const std::string& expression, int& output)
498 {
499 if (expression.empty())
500 {
501 return false;
502 }
503
504 size_t i;
505 int value;
Jatkiewicz, Joanna16bbc6b2023-11-27 10:23:29 +0100506 bool ifFormSetOperator = false;
Patrick Williamsed173c32021-10-06 13:09:19 -0500507 std::stack<int> values;
508 std::stack<knob::DepexOperators> operators;
509 std::string subExpression;
510
511 for (i = 0; i < expression.length(); i++)
512 {
513 if (expression[i] == ' ')
514 {
515 /* whitespace */
516 continue;
517 }
518 else
519 {
520 std::string word;
521
522 /* Get the next word in expression string */
523 while ((i < expression.length()) && (expression[i] != ' '))
524 {
525 word.push_back(expression[i++]);
526 }
527
528 if (word == "_OR_" || word == "OR")
529 {
530 /* OR and AND has more precedence than other operators
531 * To handle statements like "a != b or c != d"
532 * we need to execute, for above example, both '!=' before
533 * 'or' */
534 if (!operators.empty())
535 {
536 if (!evaluateExprStack(values, operators, value))
537 {
538 return false;
539 }
540
541 values.emplace(value);
542 }
543
544 operators.emplace(knob::DepexOperators::OR);
545 }
546 else if (word == "_AND_" || word == "AND")
547 {
548 /* OR and AND has more precedence than other operators
549 * To handle statements like "a == b and c == d"
550 * we need to execute, for above example, both '==' before
551 * 'and' */
552 if (!operators.empty())
553 {
554 if (!evaluateExprStack(values, operators, value))
555 {
556 return false;
557 }
558
559 values.emplace(value);
560 }
561
562 operators.emplace(knob::DepexOperators::AND);
563 }
564 else if (word == "_LTE_")
565 {
566 operators.emplace(knob::DepexOperators::LTE);
567 }
568 else if (word == "_LT_")
569 {
570 operators.emplace(knob::DepexOperators::LT);
571 }
572 else if (word == "_GTE_")
573 {
574 operators.emplace(knob::DepexOperators::GTE);
575 }
576 else if (word == "_GT_")
577 {
578 operators.emplace(knob::DepexOperators::GT);
579 }
580 else if (word == "_NEQ_")
581 {
582 operators.emplace(knob::DepexOperators::NEQ);
583 }
584 else if (word == "_EQU_")
585 {
586 operators.emplace(knob::DepexOperators::EQU);
587 }
588 else if (word == "%")
589 {
590 operators.emplace(knob::DepexOperators::MODULO);
591 }
592 else
593 {
594 /* Handle 'Sif(', 'Gif(', 'Dif(' and '('
595 * by taking the inner/sub expression and evaluating it */
596 if (word.back() == '(')
597 {
Jatkiewicz, Joanna16bbc6b2023-11-27 10:23:29 +0100598 if (word == "Sif(" || word == "Gif(" || word == "Dif(")
599 {
600 ifFormSetOperator = true;
601 }
Patrick Williamsed173c32021-10-06 13:09:19 -0500602 if (!getSubExpression(expression, subExpression, i))
603 break;
604
605 if (!evaluateExpression(subExpression, value))
606 break;
607 }
608 else if (word == "_LIST_")
609 {
610 if (!getListExpression(expression, subExpression, i))
611 break;
612
613 --i;
614
615 if (!evaluateExpression(subExpression, value))
616 break;
617 }
618 else if (word == "NOT")
619 {
620 if (!getNotValue(expression, i, value))
621 break;
622 }
623 else if (isNumber(word) || isHexNotation(word))
624 {
625 try
626 {
Jatkiewicz, Joanna16bbc6b2023-11-27 10:23:29 +0100627 value = std::stoi(word, nullptr, 0);
Patrick Williamsed173c32021-10-06 13:09:19 -0500628 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500629 catch (const std::exception& ex)
Patrick Williamsed173c32021-10-06 13:09:19 -0500630 {
631 phosphor::logging::log<
632 phosphor::logging::level::ERR>(ex.what());
633 return false;
634 }
635 }
636 else
637 {
638 if (!getValue(word, value))
639 break;
640 }
641
Jatkiewicz, Joanna16bbc6b2023-11-27 10:23:29 +0100642 /* 'Sif(', 'Gif(', 'Dif( == IF NOT,
643 we have to negate the vaule */
644 if (ifFormSetOperator == true)
645 {
646 value = !value;
647 }
Patrick Williamsed173c32021-10-06 13:09:19 -0500648 values.emplace(value);
649 }
650 }
651 }
652
653 if (i == expression.length())
654 {
655 if (evaluateExprStack(values, operators, output))
656 {
657 return true;
658 }
659 }
660
661 return false;
662 }
663
664 private:
665 /* To store all 'knob's in 'biosknobs' */
666 std::vector<knob::knob>& mKnobs;
667
668 /* To store all bad 'depex' expression */
669 std::vector<std::string> mError;
670};
671
672class Xml
673{
674 public:
675 Xml(const char* filePath) : mDepex(std::make_unique<Depex>(mKnobs))
676 {
677 if (!getKnobs(filePath))
678 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500679 std::string error = "Unable to get knobs in file: " +
680 std::string(filePath);
Patrick Williamsed173c32021-10-06 13:09:19 -0500681 throw std::runtime_error(error);
682 }
683 }
684
685 /* Fill Bios table with all 'knob's which have output of 'depex' expression
686 * as 'true' */
687 bool getBaseTable(bios::BiosBaseTableType& baseTable)
688 {
689 baseTable.clear();
690
691 for (auto& knob : mKnobs)
692 {
693 if (knob.depex)
694 {
695 std::string text =
696 "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf";
697 bios::OptionTypeVector options;
698
699 for (auto& option : knob.options)
700 {
Arun Lal K M7a8ab9e2023-05-03 12:19:22 +0000701 options.emplace_back(text, option.value, option.text);
Patrick Williamsed173c32021-10-06 13:09:19 -0500702 }
703
704 bios::BiosBaseTableTypeEntry baseTableEntry = std::make_tuple(
705 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType."
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000706 "Enumeration",
Arun Lal K M1eb3d642023-05-08 12:58:20 +0000707 false, knob.promptStr, knob.descriptionStr, "./",
Patrick Williamsed173c32021-10-06 13:09:19 -0500708 knob.currentValStr, knob.defaultStr, options);
709
710 baseTable.emplace(knob.nameStr, baseTableEntry);
711 }
712 }
713
714 if (!baseTable.empty())
715 {
716 return true;
717 }
718
719 return false;
720 }
721
722 /* Execute all 'depex' expression */
723 bool doDepexCompute()
724 {
725 mDepex->compute();
726
727 if (mDepex->getErrorCount())
728 {
729 mDepex->printError();
730 return false;
731 }
732
733 return true;
734 }
735
736 private:
737 /* Get 'option' */
738 void getOption(tinyxml2::XMLElement* pOption)
739 {
740 if (pOption)
741 {
742 std::string valueStr;
743 std::string textStr;
744
745 if (pOption->Attribute("text"))
746 valueStr = pOption->Attribute("text");
747
748 if (pOption->Attribute("value"))
749 textStr = pOption->Attribute("value");
750
751 mKnobs.back().options.emplace_back(pOption->Attribute("text"),
752 pOption->Attribute("value"));
753 }
754 }
755
756 /* Get 'options' */
757 void getOptions(tinyxml2::XMLElement* pKnob)
758 {
759 uint16_t reserveCnt = 0;
760
761 /* Get node options inside knob */
762 tinyxml2::XMLElement* pOptions = pKnob->FirstChildElement("options");
763
764 if (pOptions)
765 {
766 for (tinyxml2::XMLElement* pOption =
767 pOptions->FirstChildElement("option");
768 pOption; pOption = pOption->NextSiblingElement("option"))
769 {
770 ++reserveCnt;
771 }
772
773 mKnobs.back().options.reserve(reserveCnt);
774
775 /* Loop through all option inside options */
776 for (tinyxml2::XMLElement* pOption =
777 pOptions->FirstChildElement("option");
778 pOption; pOption = pOption->NextSiblingElement("option"))
779 {
780 getOption(pOption);
781 }
782 }
783 }
784
785 /* Get 'knob' */
786 void getKnob(tinyxml2::XMLElement* pKnob)
787 {
788 if (pKnob)
789 {
790 int currentVal = 0;
791 std::string nameStr;
792 std::string currentValStr;
793 std::string descriptionStr;
794 std::string defaultStr;
795 std::string depexStr;
796 std::string promptStr;
797 std::string setupTypeStr;
798
799 if (!pKnob->Attribute("name") || !pKnob->Attribute("CurrentVal"))
800 {
801 return;
802 }
803
804 nameStr = pKnob->Attribute("name");
805 currentValStr = pKnob->Attribute("CurrentVal");
Snehalatha Venkatesh713928b2021-12-23 09:41:59 +0000806 std::stringstream ss;
807 ss << std::hex << currentValStr;
808 if (ss.good())
Patrick Williamsed173c32021-10-06 13:09:19 -0500809 {
Snehalatha Venkatesh713928b2021-12-23 09:41:59 +0000810 ss >> currentVal;
Patrick Williamsed173c32021-10-06 13:09:19 -0500811 }
Snehalatha Venkatesh713928b2021-12-23 09:41:59 +0000812 else
Patrick Williamsed173c32021-10-06 13:09:19 -0500813 {
Snehalatha Venkatesh713928b2021-12-23 09:41:59 +0000814 std::string error = "Invalid hex value input " + currentValStr +
815 " for " + nameStr + "\n";
Patrick Williamsed173c32021-10-06 13:09:19 -0500816 phosphor::logging::log<phosphor::logging::level::ERR>(
Snehalatha Venkatesh713928b2021-12-23 09:41:59 +0000817 error.c_str());
Patrick Williamsed173c32021-10-06 13:09:19 -0500818 return;
819 }
Patrick Williamsed173c32021-10-06 13:09:19 -0500820 if (pKnob->Attribute("description"))
821 descriptionStr = pKnob->Attribute("description");
822
823 if (pKnob->Attribute("default"))
824 defaultStr = pKnob->Attribute("default");
825
826 if (pKnob->Attribute("depex"))
827 depexStr = pKnob->Attribute("depex");
828
829 if (pKnob->Attribute("prompt"))
830 promptStr = pKnob->Attribute("prompt");
831
832 if (pKnob->Attribute("setupType"))
833 setupTypeStr = pKnob->Attribute("setupType");
834
835 mKnobs.emplace_back(nameStr, currentValStr, currentVal,
836 descriptionStr, defaultStr, promptStr, depexStr,
837 setupTypeStr);
838
839 getOptions(pKnob);
840 }
841 }
842
843 /* Get 'biosknobs' */
844 bool getKnobs(const char* biosXmlFilePath)
845 {
846 uint16_t reserveCnt = 0;
847
848 mKnobs.clear();
849
850 tinyxml2::XMLDocument biosXml;
851
852 /* Load the XML file into the Doc instance */
853 biosXml.LoadFile(biosXmlFilePath);
854
855 /* Get 'SYSTEM' */
856 tinyxml2::XMLElement* pRootElement = biosXml.RootElement();
857 if (pRootElement)
858 {
859 /* Get 'biosknobs' inside 'SYSTEM' */
860 tinyxml2::XMLElement* pBiosknobs =
861 pRootElement->FirstChildElement("biosknobs");
862 if (pBiosknobs)
863 {
864 for (tinyxml2::XMLElement* pKnob =
865 pBiosknobs->FirstChildElement("knob");
866 pKnob; pKnob = pKnob->NextSiblingElement("knob"))
867 {
868 ++reserveCnt;
869 }
870
871 /* reserve before emplace_back will avoids realloc(s) */
872 mKnobs.reserve(reserveCnt);
873
874 for (tinyxml2::XMLElement* pKnob =
875 pBiosknobs->FirstChildElement("knob");
876 pKnob; pKnob = pKnob->NextSiblingElement("knob"))
877 {
878 getKnob(pKnob);
879 }
880 }
881 }
882
883 if (!mKnobs.empty())
884 {
885 return true;
886 }
887
888 return false;
889 }
890
891 private:
892 /* To store all 'knob's in 'biosknobs' */
893 std::vector<knob::knob> mKnobs;
894
895 /* Object of Depex class to compute 'depex' expression */
896 std::unique_ptr<Depex> mDepex;
897};
898} // namespace bios