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