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