Add depex support in bios.xml parsing.
Added logic to execute depex expression for every knob in bios.xml.
knob is added to BiosAttributeRegistry only if depex evaluation result
is TRUE.
Tested:
By giving GET Request to
'redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry'.
Output sample showing few knobs added becuase depex evaluation result
was TRUE:
{
"AttributeName": "AEPErrorInjEn",
"CurrentValue": "0x00",
"DefaultValue": "0x00",
"DisplayName": "AEPErrorInjEn",
"HelpText": "Enable/Disable PMem Error Injection",
"MenuPath": "./",
"ReadOnly": false,
"Type": "String",
"Value": [
{
"OneOf": "0x0"
},
{
"OneOf": "0x1"
}
]
}
{
"AttributeName": "wrVrefCenter",
"CurrentValue": "0x01",
"DefaultValue": "0x01",
"DisplayName": "wrVrefCenter",
"HelpText": "Write Vref Centering Disable/Enable",
"MenuPath": "./",
"ReadOnly": false,
"Type": "String",
"Value": [
{
"OneOf": "0x0"
},
{
"OneOf": "0x1"
}
]
}
Following are few knobs rejected becuase depex evaluation
result was FALSE:
<knob type="scalar" setupType="oneof" name="PfrProvision"
varstoreIndex="04" prompt="PFR Provision"
description="Selectable if PFR is not locked." size="1"
offset="0x0126"
depex="Sif( PfrSupported _EQU_ 0 ) _AND_ Gif( PfrLockStatus _EQU_ 1 OR
PfrProvisionStatus _EQU_ 1 )"
default="0x00" CurrentVal="0x00">
<options>
<option text="Disable" value="0x0"/>
<option text="Enable" value="0x1"/>
</options>
</knob>
<knob type="scalar" setupType="oneof" name="SataHotPlugController0_0"
varstoreIndex="01" prompt="
Hot Plug" description="Designates this port as Hot Pluggable." size="1"
offset="0x0119"
depex="Sif( PchSata_0 _EQU_ 0 ) _AND_
Sif( SataExternalController0_0 _EQU_ 1 )" default="0x00"
CurrentVal="0x00">
<options>
<option text="Disabled" value="0x0"/>
<option text="Enabled" value="0x1"/>
</options>
</knob>
Signed-off-by: Arun Lal K M <arun.lal@intel.com>
Change-Id: Iff1ea01fb06200e21cc7f2a2e0fdfdff70376581
diff --git a/include/biosxml.hpp b/include/biosxml.hpp
new file mode 100644
index 0000000..c5be53c
--- /dev/null
+++ b/include/biosxml.hpp
@@ -0,0 +1,884 @@
+#pragma once
+
+#include "tinyxml2.h"
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+
+#include <map>
+#include <sstream>
+#include <stack>
+#include <string>
+#include <variant>
+#include <vector>
+
+std::string mapAttrTypeToRedfish(const std::string_view typeDbus)
+{
+ std::string ret;
+ if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."
+ "AttributeType.Enumeration")
+ {
+ ret = "Enumeration";
+ }
+ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
+ "Manager.AttributeType.String")
+ {
+ ret = "String";
+ }
+ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
+ "Manager.AttributeType.Password")
+ {
+ ret = "Password";
+ }
+ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
+ "Manager.AttributeType.Integer")
+ {
+ ret = "Integer";
+ }
+ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
+ "Manager.AttributeType.Boolean")
+ {
+ ret = "Boolean";
+ }
+ else
+ {
+ ret = "UNKNOWN";
+ }
+
+ return ret;
+}
+
+namespace bios
+{
+/* Can hold one 'option'
+ * For example
+ * <option text="TIS" value="0x0"/>
+ */
+using OptionType = std::tuple<std::string, std::variant<int64_t, std::string>>;
+
+/* Can hold one 'options'
+ * For example
+ * <options>
+ * <option text="TIS" value="0x0"/>
+ * <option text="PTP FIFO" value="0x1"/>
+ * <option text="PTP CRB" value="0x2"/>
+ * </options>
+ */
+using OptionTypeVector = std::vector<OptionType>;
+
+/* Can hold one 'knob'
+ * For example
+ * <knob type="scalar" setupType="oneof" name="TpmDeviceInterfaceAttempt"
+ * varstoreIndex="14" prompt="Attempt PTP TPM Device Interface"
+ * description="Attempt PTP TPM Device Interface: PTP FIFO, PTP CRB" size="1"
+ * offset="0x0005" depex="Sif( _LIST_ TpmDevice _EQU_ 0 1 ) _AND_ Sif(
+ * TpmDeviceInterfacePtpFifoSupported _EQU_ 0 OR
+ * TpmDeviceInterfacePtpCrbSupported _EQU_ 0 )" default="0x00"
+ *CurrentVal="0x00"> <options> <option text="TIS" value="0x0"/> <option
+ *text="PTP FIFO" value="0x1"/> <option text="PTP CRB" value="0x2"/>
+ * </options>
+ * </knob>
+ */
+using BiosBaseTableTypeEntry =
+ std::tuple<std::string, bool, std::string, std::string, std::string,
+ std::variant<int64_t, std::string>,
+ std::variant<int64_t, std::string>, OptionTypeVector>;
+
+/* Can hold one 'biosknobs'
+ * biosknobs has array of 'knob' */
+using BiosBaseTableType = std::map<std::string, BiosBaseTableTypeEntry>;
+
+namespace knob
+{
+/* These are the operators we support in a 'depex' expression
+ * Note: We also support '_LIST_', 'Sif', 'Gif', 'Dif', and 'NOT'. But they are
+ * handeled sepeartely. */
+enum class DepexOperators
+{
+ unknown = 0,
+ OR,
+ AND,
+ LTE,
+ LT,
+ EQU,
+ NEQ,
+ MODULO
+};
+
+namespace option
+{
+/* Can hold one 'option' */
+struct option
+{
+ option(std::string text, std::string value) :
+ text(std::move(text)), value(std::move(value))
+ {}
+
+ std::string text;
+ std::string value;
+};
+} // namespace option
+
+/* Can hold one 'knob' */
+struct knob
+{
+ knob(std::string nameStr, std::string currentValStr, int currentVal,
+ std::string descriptionStr, std::string defaultStr,
+ std::string promptStr, std::string depexStr,
+ std::string& setupTypeStr) :
+ nameStr(std::move(nameStr)),
+ currentValStr(std::move(currentValStr)), currentVal(currentVal),
+ descriptionStr(std::move(descriptionStr)),
+ defaultStr(std::move(defaultStr)), promptStr(std::move(promptStr)),
+ depexStr(std::move(depexStr)), depex(false),
+ readOnly(("ReadOnly" == setupTypeStr) ? true : false)
+ {}
+
+ bool depex;
+ bool readOnly;
+ int currentVal;
+
+ std::string nameStr;
+ std::string currentValStr;
+ std::string descriptionStr;
+ std::string defaultStr;
+ std::string promptStr;
+ std::string depexStr;
+
+ /* Can hold one 'options' */
+ std::vector<option::option> options;
+};
+} // namespace knob
+
+/* Class capable of computing 'depex' expression. */
+class Depex
+{
+ public:
+ Depex(std::vector<knob::knob>& knobs) : mKnobs(knobs)
+ {}
+
+ /* Compute 'depex' expression of all knobs in 'biosknobs'. */
+ void compute()
+ {
+ mError.clear();
+
+ for (auto& knob : mKnobs)
+ {
+ /* if 'depex' == "TRUE" no need to execute expression. */
+ if ("TRUE" == knob.depexStr)
+ {
+ knob.depex = true;
+ }
+ else if (!knob.readOnly)
+ {
+ int value = 0;
+
+ if (!evaluateExpression(knob.depexStr, value))
+ {
+ mError.emplace_back("bad depex: " + knob.depexStr +
+ " in knob: " + knob.nameStr);
+ }
+ else
+ {
+ if (value)
+ {
+ knob.depex = true;
+ }
+ }
+ }
+ }
+ }
+
+ /* Returns the number of 'knob's which have a bad 'depex' expression. */
+ size_t getErrorCount()
+ {
+ return mError.size();
+ }
+
+ /* Prints all the 'knob's which have a bad 'depex' expression. */
+ void printError()
+ {
+ for (auto& error : mError)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ error.c_str());
+ }
+ }
+
+ private:
+ /* Returns 'true' if the argument string is a number. */
+ bool isNumber(const std::string& s)
+ {
+ return !s.empty() &&
+ std::find_if(s.begin(), s.end(), [](unsigned char c) {
+ return !std::isdigit(c);
+ }) == s.end();
+ }
+
+ /* Returns 'true' if the argument string is hex representation of a number.
+ */
+ bool isHexNotation(std::string const& s)
+ {
+ return s.compare(0, 2, "0x") == 0 && s.size() > 2 &&
+ s.find_first_not_of("0123456789abcdefABCDEF", 2) ==
+ std::string::npos;
+ }
+
+ /* Function to find current value of a 'knob'
+ * search is done using 'knob' attribute 'name' */
+ bool getValue(std::string& variableName, int& value)
+ {
+ for (auto& knob : mKnobs)
+ {
+ if (knob.nameStr == variableName)
+ {
+ value = knob.currentVal;
+ return true;
+ }
+ }
+
+ std::string error =
+ "Unable to find knob: " + variableName + " in knob list\n";
+ phosphor::logging::log<phosphor::logging::level::ERR>(error.c_str());
+
+ return false;
+ }
+
+ /* Get the expression enclosed within brackets, i.e., between '(' and ')' */
+ bool getSubExpression(const std::string& expression,
+ std::string& subExpression, size_t& i)
+ {
+ int level = 1;
+ subExpression.clear();
+
+ for (; i < expression.length(); i++)
+ {
+ if (expression[i] == '(')
+ {
+ ++level;
+ }
+ else if (expression[i] == ')')
+ {
+ --level;
+ if (level == 0)
+ {
+ break;
+ }
+ }
+
+ subExpression.push_back(expression[i]);
+ }
+
+ if (!subExpression.empty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /* Function to handle operator '_LIST_'
+ * Convert a '_LIST_' expression to a normal expression
+ * Example "_LIST_ VariableA _EQU_ 0 1" is converted to "VariableA _EQU_ 0
+ * OR VariableA _EQU_ 1" */
+ bool getListExpression(const std::string& expression,
+ std::string& subExpression, size_t& i)
+ {
+ subExpression.clear();
+
+ int cnt = 0;
+ std::string variableStr;
+ std::string operatorStr;
+
+ for (; i < expression.length(); i++)
+ {
+ if (expression[i] == '(')
+ {
+ return false;
+ }
+ else if (expression[i] == ')')
+ {
+ break;
+ }
+ else if (expression[i] == ' ')
+ {
+ /* whitespace */
+ continue;
+ }
+ else
+ {
+ std::string word;
+
+ /* Get the next word in expression string */
+ while ((i < expression.length()) && (expression[i] != ' '))
+ {
+ word.push_back(expression[i++]);
+ }
+
+ if (word == "_OR_" || word == "OR" || word == "_AND_" ||
+ word == "AND" || word == "NOT")
+ {
+ i = i - word.length();
+ break;
+ }
+
+ ++cnt;
+
+ if (cnt == 1)
+ {
+ variableStr = word;
+ }
+ else if (cnt == 2)
+ {
+ operatorStr = word;
+ }
+ else
+ {
+ if (cnt > 3)
+ {
+ subExpression += " OR ";
+ }
+
+ subExpression += "( ";
+ subExpression += variableStr;
+ subExpression += " ";
+ subExpression += operatorStr;
+ subExpression += " ";
+ subExpression += word;
+ subExpression += " )";
+ }
+ }
+ }
+
+ if (!subExpression.empty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /* Function to handle operator 'NOT'
+ * 1) Find the variable
+ * 2) apply NOT on the variable */
+ bool getNotValue(const std::string& expression, size_t& i, int& value)
+ {
+ std::string word;
+
+ for (; i < expression.length(); i++)
+ {
+ if (expression[i] == ' ')
+ {
+ /* whitespace */
+ continue;
+ }
+ else
+ {
+ /* Get the next word in expression string */
+ while ((i < expression.length()) && (expression[i] != ' '))
+ {
+ word.push_back(expression[i++]);
+ }
+
+ break;
+ }
+ }
+
+ if (!word.empty())
+ {
+ if (getValue(word, value))
+ {
+ value = !value;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /* 1) Pop one operator from operator stack, example 'OR'
+ * 2) Pop two variable from variable stack, example VarA and VarB
+ * 3) Push back result of 'VarA OR VarB' to variable stack
+ * 4) Repeat till operator stack is empty
+ *
+ * The last variable in variable stack is the output of the expression. */
+ bool evaluateExprStack(std::stack<int>& values,
+ std::stack<knob::DepexOperators>& operators,
+ int& output)
+ {
+ if (values.size() != (operators.size() + 1))
+ {
+ return false;
+ }
+
+ while (!operators.empty())
+ {
+ int b = values.top();
+ values.pop();
+
+ int a = values.top();
+ values.pop();
+
+ switch (operators.top())
+ {
+ case knob::DepexOperators::OR:
+ values.emplace(a | b);
+ break;
+
+ case knob::DepexOperators::AND:
+ values.emplace(a & b);
+ break;
+
+ case knob::DepexOperators::EQU:
+ if (a == b)
+ {
+ values.emplace(1);
+ break;
+ }
+
+ values.emplace(0);
+ break;
+
+ case knob::DepexOperators::NEQ:
+ if (a != b)
+ {
+ values.emplace(1);
+ break;
+ }
+
+ values.emplace(0);
+ break;
+
+ case knob::DepexOperators::LTE:
+ if (a <= b)
+ {
+ values.emplace(1);
+ break;
+ }
+
+ values.emplace(0);
+ break;
+
+ case knob::DepexOperators::LT:
+ if (a < b)
+ {
+ values.emplace(1);
+ break;
+ }
+
+ values.emplace(0);
+ break;
+
+ case knob::DepexOperators::MODULO:
+ if (b == 0)
+ {
+ return false;
+ }
+ values.emplace(a % b);
+ break;
+
+ default:
+ return false;
+ }
+
+ operators.pop();
+ }
+
+ if (values.size() == 1)
+ {
+ output = values.top();
+ values.pop();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /* Evaluvate one 'depex' expression
+ * 1) Find a word in expression string
+ * 2) If word is a variable push to variable stack
+ * 3) If word is a operator push to operator stack
+ *
+ * Execute the stack at end to get the result of expression. */
+ bool evaluateExpression(const std::string& expression, int& output)
+ {
+ if (expression.empty())
+ {
+ return false;
+ }
+
+ size_t i;
+ int value;
+ std::stack<int> values;
+ std::stack<knob::DepexOperators> operators;
+ std::string subExpression;
+
+ for (i = 0; i < expression.length(); i++)
+ {
+ if (expression[i] == ' ')
+ {
+ /* whitespace */
+ continue;
+ }
+ else
+ {
+ std::string word;
+
+ /* Get the next word in expression string */
+ while ((i < expression.length()) && (expression[i] != ' '))
+ {
+ word.push_back(expression[i++]);
+ }
+
+ if (word == "_OR_" || word == "OR")
+ {
+ /* OR and AND has more precedence than other operators
+ * To handle statements like "a != b or c != d"
+ * we need to execute, for above example, both '!=' before
+ * 'or' */
+ if (!operators.empty())
+ {
+ if (!evaluateExprStack(values, operators, value))
+ {
+ return false;
+ }
+
+ values.emplace(value);
+ }
+
+ operators.emplace(knob::DepexOperators::OR);
+ }
+ else if (word == "_AND_" || word == "AND")
+ {
+ /* OR and AND has more precedence than other operators
+ * To handle statements like "a == b and c == d"
+ * we need to execute, for above example, both '==' before
+ * 'and' */
+ if (!operators.empty())
+ {
+ if (!evaluateExprStack(values, operators, value))
+ {
+ return false;
+ }
+
+ values.emplace(value);
+ }
+
+ operators.emplace(knob::DepexOperators::AND);
+ }
+ else if (word == "_LTE_")
+ {
+ operators.emplace(knob::DepexOperators::LTE);
+ }
+ else if (word == "_LT_")
+ {
+ operators.emplace(knob::DepexOperators::LT);
+ }
+ else if (word == "_NEQ_")
+ {
+ operators.emplace(knob::DepexOperators::NEQ);
+ }
+ else if (word == "_EQU_")
+ {
+ operators.emplace(knob::DepexOperators::EQU);
+ }
+ else if (word == "%")
+ {
+ operators.emplace(knob::DepexOperators::MODULO);
+ }
+ else
+ {
+ /* Handle 'Sif(', 'Gif(', 'Dif(' and '('
+ * by taking the inner/sub expression and evaluating it */
+ if (word.back() == '(')
+ {
+ if (!getSubExpression(expression, subExpression, i))
+ break;
+
+ if (!evaluateExpression(subExpression, value))
+ break;
+ }
+ else if (word == "_LIST_")
+ {
+ if (!getListExpression(expression, subExpression, i))
+ break;
+
+ --i;
+
+ if (!evaluateExpression(subExpression, value))
+ break;
+ }
+ else if (word == "NOT")
+ {
+ if (!getNotValue(expression, i, value))
+ break;
+ }
+ else if (isNumber(word) || isHexNotation(word))
+ {
+ try
+ {
+ value = std::stoi(word);
+ }
+ catch (std::exception& ex)
+ {
+ phosphor::logging::log<
+ phosphor::logging::level::ERR>(ex.what());
+ return false;
+ }
+ }
+ else
+ {
+ if (!getValue(word, value))
+ break;
+ }
+
+ values.emplace(value);
+ }
+ }
+ }
+
+ if (i == expression.length())
+ {
+ if (evaluateExprStack(values, operators, output))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private:
+ /* To store all 'knob's in 'biosknobs' */
+ std::vector<knob::knob>& mKnobs;
+
+ /* To store all bad 'depex' expression */
+ std::vector<std::string> mError;
+};
+
+class Xml
+{
+ public:
+ Xml(const char* filePath) : mDepex(std::make_unique<Depex>(mKnobs))
+ {
+ if (!getKnobs(filePath))
+ {
+ std::string error =
+ "Unable to get knobs in file: " + std::string(filePath);
+ throw std::runtime_error(error);
+ }
+ }
+
+ /* Fill Bios table with all 'knob's which have output of 'depex' expression
+ * as 'true' */
+ bool getBaseTable(bios::BiosBaseTableType& baseTable)
+ {
+ baseTable.clear();
+
+ for (auto& knob : mKnobs)
+ {
+ if (knob.depex)
+ {
+ std::string text =
+ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf";
+ bios::OptionTypeVector options;
+
+ for (auto& option : knob.options)
+ {
+ options.emplace_back(text, option.value);
+ }
+
+ bios::BiosBaseTableTypeEntry baseTableEntry = std::make_tuple(
+ "xyz.openbmc_project.BIOSConfig.Manager.AttributeType."
+ "String",
+ false, knob.nameStr, knob.descriptionStr, "./",
+ knob.currentValStr, knob.defaultStr, options);
+
+ baseTable.emplace(knob.nameStr, baseTableEntry);
+ }
+ }
+
+ if (!baseTable.empty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /* Execute all 'depex' expression */
+ bool doDepexCompute()
+ {
+ mDepex->compute();
+
+ if (mDepex->getErrorCount())
+ {
+ mDepex->printError();
+ return false;
+ }
+
+ return true;
+ }
+
+ private:
+ /* Get 'option' */
+ void getOption(tinyxml2::XMLElement* pOption)
+ {
+ if (pOption)
+ {
+ std::string valueStr;
+ std::string textStr;
+
+ if (pOption->Attribute("text"))
+ valueStr = pOption->Attribute("text");
+
+ if (pOption->Attribute("value"))
+ textStr = pOption->Attribute("value");
+
+ mKnobs.back().options.emplace_back(pOption->Attribute("text"),
+ pOption->Attribute("value"));
+ }
+ }
+
+ /* Get 'options' */
+ void getOptions(tinyxml2::XMLElement* pKnob)
+ {
+ uint16_t reserveCnt = 0;
+
+ /* Get node options inside knob */
+ tinyxml2::XMLElement* pOptions = pKnob->FirstChildElement("options");
+
+ if (pOptions)
+ {
+ for (tinyxml2::XMLElement* pOption =
+ pOptions->FirstChildElement("option");
+ pOption; pOption = pOption->NextSiblingElement("option"))
+ {
+ ++reserveCnt;
+ }
+
+ mKnobs.back().options.reserve(reserveCnt);
+
+ /* Loop through all option inside options */
+ for (tinyxml2::XMLElement* pOption =
+ pOptions->FirstChildElement("option");
+ pOption; pOption = pOption->NextSiblingElement("option"))
+ {
+ getOption(pOption);
+ }
+ }
+ }
+
+ /* Get 'knob' */
+ void getKnob(tinyxml2::XMLElement* pKnob)
+ {
+ if (pKnob)
+ {
+ int currentVal = 0;
+ std::string nameStr;
+ std::string currentValStr;
+ std::string descriptionStr;
+ std::string defaultStr;
+ std::string depexStr;
+ std::string promptStr;
+ std::string setupTypeStr;
+
+ if (!pKnob->Attribute("name") || !pKnob->Attribute("CurrentVal"))
+ {
+ return;
+ }
+
+ nameStr = pKnob->Attribute("name");
+ currentValStr = pKnob->Attribute("CurrentVal");
+
+ try
+ {
+ currentVal = std::stoi(currentValStr);
+ }
+ catch (std::exception& ex)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ ex.what());
+ return;
+ }
+
+ if (pKnob->Attribute("description"))
+ descriptionStr = pKnob->Attribute("description");
+
+ if (pKnob->Attribute("default"))
+ defaultStr = pKnob->Attribute("default");
+
+ if (pKnob->Attribute("depex"))
+ depexStr = pKnob->Attribute("depex");
+
+ if (pKnob->Attribute("prompt"))
+ promptStr = pKnob->Attribute("prompt");
+
+ if (pKnob->Attribute("setupType"))
+ setupTypeStr = pKnob->Attribute("setupType");
+
+ mKnobs.emplace_back(nameStr, currentValStr, currentVal,
+ descriptionStr, defaultStr, promptStr, depexStr,
+ setupTypeStr);
+
+ getOptions(pKnob);
+ }
+ }
+
+ /* Get 'biosknobs' */
+ bool getKnobs(const char* biosXmlFilePath)
+ {
+ uint16_t reserveCnt = 0;
+
+ mKnobs.clear();
+
+ tinyxml2::XMLDocument biosXml;
+
+ /* Load the XML file into the Doc instance */
+ biosXml.LoadFile(biosXmlFilePath);
+
+ /* Get 'SYSTEM' */
+ tinyxml2::XMLElement* pRootElement = biosXml.RootElement();
+ if (pRootElement)
+ {
+ /* Get 'biosknobs' inside 'SYSTEM' */
+ tinyxml2::XMLElement* pBiosknobs =
+ pRootElement->FirstChildElement("biosknobs");
+ if (pBiosknobs)
+ {
+ for (tinyxml2::XMLElement* pKnob =
+ pBiosknobs->FirstChildElement("knob");
+ pKnob; pKnob = pKnob->NextSiblingElement("knob"))
+ {
+ ++reserveCnt;
+ }
+
+ /* reserve before emplace_back will avoids realloc(s) */
+ mKnobs.reserve(reserveCnt);
+
+ for (tinyxml2::XMLElement* pKnob =
+ pBiosknobs->FirstChildElement("knob");
+ pKnob; pKnob = pKnob->NextSiblingElement("knob"))
+ {
+ getKnob(pKnob);
+ }
+ }
+ }
+
+ if (!mKnobs.empty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ /* To store all 'knob's in 'biosknobs' */
+ std::vector<knob::knob> mKnobs;
+
+ /* Object of Depex class to compute 'depex' expression */
+ std::unique_ptr<Depex> mDepex;
+};
+} // namespace bios