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> 7e7725610SArun Lal K M 8e7725610SArun Lal K M #include <map> 9e7725610SArun Lal K M #include <sstream> 10e7725610SArun Lal K M #include <stack> 11e7725610SArun Lal K M #include <string> 12e7725610SArun Lal K M #include <variant> 13e7725610SArun Lal K M #include <vector> 14e7725610SArun Lal K M 15e7725610SArun Lal K M namespace bios 16e7725610SArun Lal K M { 17e7725610SArun Lal K M /* Can hold one 'option' 18e7725610SArun Lal K M * For example 19e7725610SArun Lal K M * <option text="TIS" value="0x0"/> 20e7725610SArun Lal K M */ 21e7725610SArun Lal K M using OptionType = std::tuple<std::string, std::variant<int64_t, std::string>>; 22e7725610SArun Lal K M 23e7725610SArun Lal K M /* Can hold one 'options' 24e7725610SArun Lal K M * For example 25e7725610SArun Lal K M * <options> 26e7725610SArun Lal K M * <option text="TIS" value="0x0"/> 27e7725610SArun Lal K M * <option text="PTP FIFO" value="0x1"/> 28e7725610SArun Lal K M * <option text="PTP CRB" value="0x2"/> 29e7725610SArun Lal K M * </options> 30e7725610SArun Lal K M */ 31e7725610SArun Lal K M using OptionTypeVector = std::vector<OptionType>; 32e7725610SArun Lal K M 33e7725610SArun Lal K M /* Can hold one 'knob' 34e7725610SArun Lal K M * For example 35e7725610SArun Lal K M * <knob type="scalar" setupType="oneof" name="TpmDeviceInterfaceAttempt" 36e7725610SArun Lal K M * varstoreIndex="14" prompt="Attempt PTP TPM Device Interface" 37e7725610SArun Lal K M * description="Attempt PTP TPM Device Interface: PTP FIFO, PTP CRB" size="1" 38e7725610SArun Lal K M * offset="0x0005" depex="Sif( _LIST_ TpmDevice _EQU_ 0 1 ) _AND_ Sif( 39e7725610SArun Lal K M * TpmDeviceInterfacePtpFifoSupported _EQU_ 0 OR 40e7725610SArun Lal K M * TpmDeviceInterfacePtpCrbSupported _EQU_ 0 )" default="0x00" 41e7725610SArun Lal K M *CurrentVal="0x00"> <options> <option text="TIS" value="0x0"/> <option 42e7725610SArun Lal K M *text="PTP FIFO" value="0x1"/> <option text="PTP CRB" value="0x2"/> 43e7725610SArun Lal K M * </options> 44e7725610SArun Lal K M * </knob> 45e7725610SArun Lal K M */ 46e7725610SArun Lal K M using BiosBaseTableTypeEntry = 47e7725610SArun Lal K M std::tuple<std::string, bool, std::string, std::string, std::string, 48e7725610SArun Lal K M std::variant<int64_t, std::string>, 49e7725610SArun Lal K M std::variant<int64_t, std::string>, 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, 65*e83c70aaSArun Lal K M GT, 66*e83c70aaSArun 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 { 79e7725610SArun 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 { 91e7725610SArun 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) : 95e7725610SArun Lal K M nameStr(std::move(nameStr)), 96e7725610SArun Lal K M currentValStr(std::move(currentValStr)), currentVal(currentVal), 97e7725610SArun Lal K M descriptionStr(std::move(descriptionStr)), 98e7725610SArun Lal K M defaultStr(std::move(defaultStr)), promptStr(std::move(promptStr)), 99e7725610SArun Lal K M depexStr(std::move(depexStr)), depex(false), 100e7725610SArun Lal K M readOnly(("ReadOnly" == setupTypeStr) ? true : false) 101e7725610SArun Lal K M {} 102e7725610SArun Lal K M 103e7725610SArun Lal K M bool depex; 104e7725610SArun Lal K M bool readOnly; 105e7725610SArun Lal K M int currentVal; 106e7725610SArun Lal K M 107e7725610SArun Lal K M std::string nameStr; 108e7725610SArun Lal K M std::string currentValStr; 109e7725610SArun Lal K M std::string descriptionStr; 110e7725610SArun Lal K M std::string defaultStr; 111e7725610SArun Lal K M std::string promptStr; 112e7725610SArun Lal K M std::string depexStr; 113e7725610SArun Lal K M 114e7725610SArun Lal K M /* Can hold one 'options' */ 115e7725610SArun Lal K M std::vector<option::option> options; 116e7725610SArun Lal K M }; 117e7725610SArun Lal K M } // namespace knob 118e7725610SArun Lal K M 119e7725610SArun Lal K M /* Class capable of computing 'depex' expression. */ 120e7725610SArun Lal K M class Depex 121e7725610SArun Lal K M { 122e7725610SArun Lal K M public: 123e7725610SArun Lal K M Depex(std::vector<knob::knob>& knobs) : mKnobs(knobs) 124e7725610SArun Lal K M {} 125e7725610SArun Lal K M 126e7725610SArun Lal K M /* Compute 'depex' expression of all knobs in 'biosknobs'. */ 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. */ 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. */ 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. */ 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 */ 186e7725610SArun Lal K M bool isHexNotation(std::string const& 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' */ 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 206e7725610SArun Lal K M std::string error = 207e7725610SArun Lal K M "Unable to find knob: " + variableName + " 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 ')' */ 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" */ 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 { 305e7725610SArun Lal K M subExpression += " OR "; 306e7725610SArun Lal K M } 307e7725610SArun Lal K M 308e7725610SArun Lal K M subExpression += "( "; 309e7725610SArun Lal K M subExpression += variableStr; 310e7725610SArun Lal K M subExpression += " "; 311e7725610SArun Lal K M subExpression += operatorStr; 312e7725610SArun Lal K M subExpression += " "; 313e7725610SArun Lal K M subExpression += word; 314e7725610SArun Lal K M subExpression += " )"; 315e7725610SArun Lal K M } 316e7725610SArun Lal K M } 317e7725610SArun Lal K M } 318e7725610SArun Lal K M 319e7725610SArun Lal K M if (!subExpression.empty()) 320e7725610SArun Lal K M { 321e7725610SArun Lal K M return true; 322e7725610SArun Lal K M } 323e7725610SArun Lal K M 324e7725610SArun Lal K M return false; 325e7725610SArun Lal K M } 326e7725610SArun Lal K M 327e7725610SArun Lal K M /* Function to handle operator 'NOT' 328e7725610SArun Lal K M * 1) Find the variable 329e7725610SArun Lal K M * 2) apply NOT on the variable */ 330e7725610SArun Lal K M bool getNotValue(const std::string& expression, size_t& i, int& value) 331e7725610SArun Lal K M { 332e7725610SArun Lal K M std::string word; 333e7725610SArun Lal K M 334e7725610SArun Lal K M for (; i < expression.length(); i++) 335e7725610SArun Lal K M { 336e7725610SArun Lal K M if (expression[i] == ' ') 337e7725610SArun Lal K M { 338e7725610SArun Lal K M /* whitespace */ 339e7725610SArun Lal K M continue; 340e7725610SArun Lal K M } 341e7725610SArun Lal K M else 342e7725610SArun Lal K M { 343e7725610SArun Lal K M /* Get the next word in expression string */ 344e7725610SArun Lal K M while ((i < expression.length()) && (expression[i] != ' ')) 345e7725610SArun Lal K M { 346e7725610SArun Lal K M word.push_back(expression[i++]); 347e7725610SArun Lal K M } 348e7725610SArun Lal K M 349e7725610SArun Lal K M break; 350e7725610SArun Lal K M } 351e7725610SArun Lal K M } 352e7725610SArun Lal K M 353e7725610SArun Lal K M if (!word.empty()) 354e7725610SArun Lal K M { 355e7725610SArun Lal K M if (getValue(word, value)) 356e7725610SArun Lal K M { 357e7725610SArun Lal K M value = !value; 358e7725610SArun Lal K M return true; 359e7725610SArun Lal K M } 360e7725610SArun Lal K M } 361e7725610SArun Lal K M 362e7725610SArun Lal K M return false; 363e7725610SArun Lal K M } 364e7725610SArun Lal K M 365e7725610SArun Lal K M /* 1) Pop one operator from operator stack, example 'OR' 366e7725610SArun Lal K M * 2) Pop two variable from variable stack, example VarA and VarB 367e7725610SArun Lal K M * 3) Push back result of 'VarA OR VarB' to variable stack 368e7725610SArun Lal K M * 4) Repeat till operator stack is empty 369e7725610SArun Lal K M * 370e7725610SArun Lal K M * The last variable in variable stack is the output of the expression. */ 371e7725610SArun Lal K M bool evaluateExprStack(std::stack<int>& values, 372e7725610SArun Lal K M std::stack<knob::DepexOperators>& operators, 373e7725610SArun Lal K M int& output) 374e7725610SArun Lal K M { 375e7725610SArun Lal K M if (values.size() != (operators.size() + 1)) 376e7725610SArun Lal K M { 377e7725610SArun Lal K M return false; 378e7725610SArun Lal K M } 379e7725610SArun Lal K M 380e7725610SArun Lal K M while (!operators.empty()) 381e7725610SArun Lal K M { 382e7725610SArun Lal K M int b = values.top(); 383e7725610SArun Lal K M values.pop(); 384e7725610SArun Lal K M 385e7725610SArun Lal K M int a = values.top(); 386e7725610SArun Lal K M values.pop(); 387e7725610SArun Lal K M 388e7725610SArun Lal K M switch (operators.top()) 389e7725610SArun Lal K M { 390e7725610SArun Lal K M case knob::DepexOperators::OR: 391e7725610SArun Lal K M values.emplace(a | b); 392e7725610SArun Lal K M break; 393e7725610SArun Lal K M 394e7725610SArun Lal K M case knob::DepexOperators::AND: 395e7725610SArun Lal K M values.emplace(a & b); 396e7725610SArun Lal K M break; 397e7725610SArun Lal K M 398e7725610SArun Lal K M case knob::DepexOperators::EQU: 399e7725610SArun Lal K M if (a == b) 400e7725610SArun Lal K M { 401e7725610SArun Lal K M values.emplace(1); 402e7725610SArun Lal K M break; 403e7725610SArun Lal K M } 404e7725610SArun Lal K M 405e7725610SArun Lal K M values.emplace(0); 406e7725610SArun Lal K M break; 407e7725610SArun Lal K M 408e7725610SArun Lal K M case knob::DepexOperators::NEQ: 409e7725610SArun Lal K M if (a != b) 410e7725610SArun Lal K M { 411e7725610SArun Lal K M values.emplace(1); 412e7725610SArun Lal K M break; 413e7725610SArun Lal K M } 414e7725610SArun Lal K M 415e7725610SArun Lal K M values.emplace(0); 416e7725610SArun Lal K M break; 417e7725610SArun Lal K M 418e7725610SArun Lal K M case knob::DepexOperators::LTE: 419e7725610SArun Lal K M if (a <= b) 420e7725610SArun Lal K M { 421e7725610SArun Lal K M values.emplace(1); 422e7725610SArun Lal K M break; 423e7725610SArun Lal K M } 424e7725610SArun Lal K M 425e7725610SArun Lal K M values.emplace(0); 426e7725610SArun Lal K M break; 427e7725610SArun Lal K M 428e7725610SArun Lal K M case knob::DepexOperators::LT: 429e7725610SArun Lal K M if (a < b) 430e7725610SArun Lal K M { 431e7725610SArun Lal K M values.emplace(1); 432e7725610SArun Lal K M break; 433e7725610SArun Lal K M } 434e7725610SArun Lal K M 435e7725610SArun Lal K M values.emplace(0); 436e7725610SArun Lal K M break; 437e7725610SArun Lal K M 438*e83c70aaSArun Lal K M case knob::DepexOperators::GTE: 439*e83c70aaSArun Lal K M if (a >= b) 440*e83c70aaSArun Lal K M { 441*e83c70aaSArun Lal K M values.emplace(1); 442*e83c70aaSArun Lal K M break; 443*e83c70aaSArun Lal K M } 444*e83c70aaSArun Lal K M 445*e83c70aaSArun Lal K M values.emplace(0); 446*e83c70aaSArun Lal K M break; 447*e83c70aaSArun Lal K M 448*e83c70aaSArun Lal K M case knob::DepexOperators::GT: 449*e83c70aaSArun Lal K M if (a > b) 450*e83c70aaSArun Lal K M { 451*e83c70aaSArun Lal K M values.emplace(1); 452*e83c70aaSArun Lal K M break; 453*e83c70aaSArun Lal K M } 454*e83c70aaSArun Lal K M 455*e83c70aaSArun Lal K M values.emplace(0); 456*e83c70aaSArun Lal K M break; 457*e83c70aaSArun Lal K M 458e7725610SArun Lal K M case knob::DepexOperators::MODULO: 459e7725610SArun Lal K M if (b == 0) 460e7725610SArun Lal K M { 461e7725610SArun Lal K M return false; 462e7725610SArun Lal K M } 463e7725610SArun Lal K M values.emplace(a % b); 464e7725610SArun Lal K M break; 465e7725610SArun Lal K M 466e7725610SArun Lal K M default: 467e7725610SArun Lal K M return false; 468e7725610SArun Lal K M } 469e7725610SArun Lal K M 470e7725610SArun Lal K M operators.pop(); 471e7725610SArun Lal K M } 472e7725610SArun Lal K M 473e7725610SArun Lal K M if (values.size() == 1) 474e7725610SArun Lal K M { 475e7725610SArun Lal K M output = values.top(); 476e7725610SArun Lal K M values.pop(); 477e7725610SArun Lal K M 478e7725610SArun Lal K M return true; 479e7725610SArun Lal K M } 480e7725610SArun Lal K M 481e7725610SArun Lal K M return false; 482e7725610SArun Lal K M } 483e7725610SArun Lal K M 484e7725610SArun Lal K M /* Evaluvate one 'depex' expression 485e7725610SArun Lal K M * 1) Find a word in expression string 486e7725610SArun Lal K M * 2) If word is a variable push to variable stack 487e7725610SArun Lal K M * 3) If word is a operator push to operator stack 488e7725610SArun Lal K M * 489e7725610SArun Lal K M * Execute the stack at end to get the result of expression. */ 490e7725610SArun Lal K M bool evaluateExpression(const std::string& expression, int& output) 491e7725610SArun Lal K M { 492e7725610SArun Lal K M if (expression.empty()) 493e7725610SArun Lal K M { 494e7725610SArun Lal K M return false; 495e7725610SArun Lal K M } 496e7725610SArun Lal K M 497e7725610SArun Lal K M size_t i; 498e7725610SArun Lal K M int value; 499e7725610SArun Lal K M std::stack<int> values; 500e7725610SArun Lal K M std::stack<knob::DepexOperators> operators; 501e7725610SArun Lal K M std::string subExpression; 502e7725610SArun Lal K M 503e7725610SArun Lal K M for (i = 0; i < expression.length(); i++) 504e7725610SArun Lal K M { 505e7725610SArun Lal K M if (expression[i] == ' ') 506e7725610SArun Lal K M { 507e7725610SArun Lal K M /* whitespace */ 508e7725610SArun Lal K M continue; 509e7725610SArun Lal K M } 510e7725610SArun Lal K M else 511e7725610SArun Lal K M { 512e7725610SArun Lal K M std::string word; 513e7725610SArun Lal K M 514e7725610SArun Lal K M /* Get the next word in expression string */ 515e7725610SArun Lal K M while ((i < expression.length()) && (expression[i] != ' ')) 516e7725610SArun Lal K M { 517e7725610SArun Lal K M word.push_back(expression[i++]); 518e7725610SArun Lal K M } 519e7725610SArun Lal K M 520e7725610SArun Lal K M if (word == "_OR_" || word == "OR") 521e7725610SArun Lal K M { 522e7725610SArun Lal K M /* OR and AND has more precedence than other operators 523e7725610SArun Lal K M * To handle statements like "a != b or c != d" 524e7725610SArun Lal K M * we need to execute, for above example, both '!=' before 525e7725610SArun Lal K M * 'or' */ 526e7725610SArun Lal K M if (!operators.empty()) 527e7725610SArun Lal K M { 528e7725610SArun Lal K M if (!evaluateExprStack(values, operators, value)) 529e7725610SArun Lal K M { 530e7725610SArun Lal K M return false; 531e7725610SArun Lal K M } 532e7725610SArun Lal K M 533e7725610SArun Lal K M values.emplace(value); 534e7725610SArun Lal K M } 535e7725610SArun Lal K M 536e7725610SArun Lal K M operators.emplace(knob::DepexOperators::OR); 537e7725610SArun Lal K M } 538e7725610SArun Lal K M else if (word == "_AND_" || word == "AND") 539e7725610SArun Lal K M { 540e7725610SArun Lal K M /* OR and AND has more precedence than other operators 541e7725610SArun Lal K M * To handle statements like "a == b and c == d" 542e7725610SArun Lal K M * we need to execute, for above example, both '==' before 543e7725610SArun Lal K M * 'and' */ 544e7725610SArun Lal K M if (!operators.empty()) 545e7725610SArun Lal K M { 546e7725610SArun Lal K M if (!evaluateExprStack(values, operators, value)) 547e7725610SArun Lal K M { 548e7725610SArun Lal K M return false; 549e7725610SArun Lal K M } 550e7725610SArun Lal K M 551e7725610SArun Lal K M values.emplace(value); 552e7725610SArun Lal K M } 553e7725610SArun Lal K M 554e7725610SArun Lal K M operators.emplace(knob::DepexOperators::AND); 555e7725610SArun Lal K M } 556e7725610SArun Lal K M else if (word == "_LTE_") 557e7725610SArun Lal K M { 558e7725610SArun Lal K M operators.emplace(knob::DepexOperators::LTE); 559e7725610SArun Lal K M } 560e7725610SArun Lal K M else if (word == "_LT_") 561e7725610SArun Lal K M { 562e7725610SArun Lal K M operators.emplace(knob::DepexOperators::LT); 563e7725610SArun Lal K M } 564*e83c70aaSArun Lal K M else if (word == "_GTE_") 565*e83c70aaSArun Lal K M { 566*e83c70aaSArun Lal K M operators.emplace(knob::DepexOperators::GTE); 567*e83c70aaSArun Lal K M } 568*e83c70aaSArun Lal K M else if (word == "_GT_") 569*e83c70aaSArun Lal K M { 570*e83c70aaSArun Lal K M operators.emplace(knob::DepexOperators::GT); 571*e83c70aaSArun Lal K M } 572e7725610SArun Lal K M else if (word == "_NEQ_") 573e7725610SArun Lal K M { 574e7725610SArun Lal K M operators.emplace(knob::DepexOperators::NEQ); 575e7725610SArun Lal K M } 576e7725610SArun Lal K M else if (word == "_EQU_") 577e7725610SArun Lal K M { 578e7725610SArun Lal K M operators.emplace(knob::DepexOperators::EQU); 579e7725610SArun Lal K M } 580e7725610SArun Lal K M else if (word == "%") 581e7725610SArun Lal K M { 582e7725610SArun Lal K M operators.emplace(knob::DepexOperators::MODULO); 583e7725610SArun Lal K M } 584e7725610SArun Lal K M else 585e7725610SArun Lal K M { 586e7725610SArun Lal K M /* Handle 'Sif(', 'Gif(', 'Dif(' and '(' 587e7725610SArun Lal K M * by taking the inner/sub expression and evaluating it */ 588e7725610SArun Lal K M if (word.back() == '(') 589e7725610SArun Lal K M { 590e7725610SArun Lal K M if (!getSubExpression(expression, subExpression, i)) 591e7725610SArun Lal K M break; 592e7725610SArun Lal K M 593e7725610SArun Lal K M if (!evaluateExpression(subExpression, value)) 594e7725610SArun Lal K M break; 595e7725610SArun Lal K M } 596e7725610SArun Lal K M else if (word == "_LIST_") 597e7725610SArun Lal K M { 598e7725610SArun Lal K M if (!getListExpression(expression, subExpression, i)) 599e7725610SArun Lal K M break; 600e7725610SArun Lal K M 601e7725610SArun Lal K M --i; 602e7725610SArun Lal K M 603e7725610SArun Lal K M if (!evaluateExpression(subExpression, value)) 604e7725610SArun Lal K M break; 605e7725610SArun Lal K M } 606e7725610SArun Lal K M else if (word == "NOT") 607e7725610SArun Lal K M { 608e7725610SArun Lal K M if (!getNotValue(expression, i, value)) 609e7725610SArun Lal K M break; 610e7725610SArun Lal K M } 611e7725610SArun Lal K M else if (isNumber(word) || isHexNotation(word)) 612e7725610SArun Lal K M { 613e7725610SArun Lal K M try 614e7725610SArun Lal K M { 615e7725610SArun Lal K M value = std::stoi(word); 616e7725610SArun Lal K M } 617e7725610SArun Lal K M catch (std::exception& ex) 618e7725610SArun Lal K M { 619e7725610SArun Lal K M phosphor::logging::log< 620e7725610SArun Lal K M phosphor::logging::level::ERR>(ex.what()); 621e7725610SArun Lal K M return false; 622e7725610SArun Lal K M } 623e7725610SArun Lal K M } 624e7725610SArun Lal K M else 625e7725610SArun Lal K M { 626e7725610SArun Lal K M if (!getValue(word, value)) 627e7725610SArun Lal K M break; 628e7725610SArun Lal K M } 629e7725610SArun Lal K M 630e7725610SArun Lal K M values.emplace(value); 631e7725610SArun Lal K M } 632e7725610SArun Lal K M } 633e7725610SArun Lal K M } 634e7725610SArun Lal K M 635e7725610SArun Lal K M if (i == expression.length()) 636e7725610SArun Lal K M { 637e7725610SArun Lal K M if (evaluateExprStack(values, operators, output)) 638e7725610SArun Lal K M { 639e7725610SArun Lal K M return true; 640e7725610SArun Lal K M } 641e7725610SArun Lal K M } 642e7725610SArun Lal K M 643e7725610SArun Lal K M return false; 644e7725610SArun Lal K M } 645e7725610SArun Lal K M 646e7725610SArun Lal K M private: 647e7725610SArun Lal K M /* To store all 'knob's in 'biosknobs' */ 648e7725610SArun Lal K M std::vector<knob::knob>& mKnobs; 649e7725610SArun Lal K M 650e7725610SArun Lal K M /* To store all bad 'depex' expression */ 651e7725610SArun Lal K M std::vector<std::string> mError; 652e7725610SArun Lal K M }; 653e7725610SArun Lal K M 654e7725610SArun Lal K M class Xml 655e7725610SArun Lal K M { 656e7725610SArun Lal K M public: 657e7725610SArun Lal K M Xml(const char* filePath) : mDepex(std::make_unique<Depex>(mKnobs)) 658e7725610SArun Lal K M { 659e7725610SArun Lal K M if (!getKnobs(filePath)) 660e7725610SArun Lal K M { 661e7725610SArun Lal K M std::string error = 662e7725610SArun Lal K M "Unable to get knobs in file: " + std::string(filePath); 663e7725610SArun Lal K M throw std::runtime_error(error); 664e7725610SArun Lal K M } 665e7725610SArun Lal K M } 666e7725610SArun Lal K M 667e7725610SArun Lal K M /* Fill Bios table with all 'knob's which have output of 'depex' expression 668e7725610SArun Lal K M * as 'true' */ 669e7725610SArun Lal K M bool getBaseTable(bios::BiosBaseTableType& baseTable) 670e7725610SArun Lal K M { 671e7725610SArun Lal K M baseTable.clear(); 672e7725610SArun Lal K M 673e7725610SArun Lal K M for (auto& knob : mKnobs) 674e7725610SArun Lal K M { 675e7725610SArun Lal K M if (knob.depex) 676e7725610SArun Lal K M { 677e7725610SArun Lal K M std::string text = 678e7725610SArun Lal K M "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf"; 679e7725610SArun Lal K M bios::OptionTypeVector options; 680e7725610SArun Lal K M 681e7725610SArun Lal K M for (auto& option : knob.options) 682e7725610SArun Lal K M { 683e7725610SArun Lal K M options.emplace_back(text, option.value); 684e7725610SArun Lal K M } 685e7725610SArun Lal K M 686e7725610SArun Lal K M bios::BiosBaseTableTypeEntry baseTableEntry = std::make_tuple( 687e7725610SArun Lal K M "xyz.openbmc_project.BIOSConfig.Manager.AttributeType." 688e7725610SArun Lal K M "String", 689e7725610SArun Lal K M false, knob.nameStr, knob.descriptionStr, "./", 690e7725610SArun Lal K M knob.currentValStr, knob.defaultStr, options); 691e7725610SArun Lal K M 692e7725610SArun Lal K M baseTable.emplace(knob.nameStr, baseTableEntry); 693e7725610SArun Lal K M } 694e7725610SArun Lal K M } 695e7725610SArun Lal K M 696e7725610SArun Lal K M if (!baseTable.empty()) 697e7725610SArun Lal K M { 698e7725610SArun Lal K M return true; 699e7725610SArun Lal K M } 700e7725610SArun Lal K M 701e7725610SArun Lal K M return false; 702e7725610SArun Lal K M } 703e7725610SArun Lal K M 704e7725610SArun Lal K M /* Execute all 'depex' expression */ 705e7725610SArun Lal K M bool doDepexCompute() 706e7725610SArun Lal K M { 707e7725610SArun Lal K M mDepex->compute(); 708e7725610SArun Lal K M 709e7725610SArun Lal K M if (mDepex->getErrorCount()) 710e7725610SArun Lal K M { 711e7725610SArun Lal K M mDepex->printError(); 712e7725610SArun Lal K M return false; 713e7725610SArun Lal K M } 714e7725610SArun Lal K M 715e7725610SArun Lal K M return true; 716e7725610SArun Lal K M } 717e7725610SArun Lal K M 718e7725610SArun Lal K M private: 719e7725610SArun Lal K M /* Get 'option' */ 720e7725610SArun Lal K M void getOption(tinyxml2::XMLElement* pOption) 721e7725610SArun Lal K M { 722e7725610SArun Lal K M if (pOption) 723e7725610SArun Lal K M { 724e7725610SArun Lal K M std::string valueStr; 725e7725610SArun Lal K M std::string textStr; 726e7725610SArun Lal K M 727e7725610SArun Lal K M if (pOption->Attribute("text")) 728e7725610SArun Lal K M valueStr = pOption->Attribute("text"); 729e7725610SArun Lal K M 730e7725610SArun Lal K M if (pOption->Attribute("value")) 731e7725610SArun Lal K M textStr = pOption->Attribute("value"); 732e7725610SArun Lal K M 733e7725610SArun Lal K M mKnobs.back().options.emplace_back(pOption->Attribute("text"), 734e7725610SArun Lal K M pOption->Attribute("value")); 735e7725610SArun Lal K M } 736e7725610SArun Lal K M } 737e7725610SArun Lal K M 738e7725610SArun Lal K M /* Get 'options' */ 739e7725610SArun Lal K M void getOptions(tinyxml2::XMLElement* pKnob) 740e7725610SArun Lal K M { 741e7725610SArun Lal K M uint16_t reserveCnt = 0; 742e7725610SArun Lal K M 743e7725610SArun Lal K M /* Get node options inside knob */ 744e7725610SArun Lal K M tinyxml2::XMLElement* pOptions = pKnob->FirstChildElement("options"); 745e7725610SArun Lal K M 746e7725610SArun Lal K M if (pOptions) 747e7725610SArun Lal K M { 748e7725610SArun Lal K M for (tinyxml2::XMLElement* pOption = 749e7725610SArun Lal K M pOptions->FirstChildElement("option"); 750e7725610SArun Lal K M pOption; pOption = pOption->NextSiblingElement("option")) 751e7725610SArun Lal K M { 752e7725610SArun Lal K M ++reserveCnt; 753e7725610SArun Lal K M } 754e7725610SArun Lal K M 755e7725610SArun Lal K M mKnobs.back().options.reserve(reserveCnt); 756e7725610SArun Lal K M 757e7725610SArun Lal K M /* Loop through all option inside options */ 758e7725610SArun Lal K M for (tinyxml2::XMLElement* pOption = 759e7725610SArun Lal K M pOptions->FirstChildElement("option"); 760e7725610SArun Lal K M pOption; pOption = pOption->NextSiblingElement("option")) 761e7725610SArun Lal K M { 762e7725610SArun Lal K M getOption(pOption); 763e7725610SArun Lal K M } 764e7725610SArun Lal K M } 765e7725610SArun Lal K M } 766e7725610SArun Lal K M 767e7725610SArun Lal K M /* Get 'knob' */ 768e7725610SArun Lal K M void getKnob(tinyxml2::XMLElement* pKnob) 769e7725610SArun Lal K M { 770e7725610SArun Lal K M if (pKnob) 771e7725610SArun Lal K M { 772e7725610SArun Lal K M int currentVal = 0; 773e7725610SArun Lal K M std::string nameStr; 774e7725610SArun Lal K M std::string currentValStr; 775e7725610SArun Lal K M std::string descriptionStr; 776e7725610SArun Lal K M std::string defaultStr; 777e7725610SArun Lal K M std::string depexStr; 778e7725610SArun Lal K M std::string promptStr; 779e7725610SArun Lal K M std::string setupTypeStr; 780e7725610SArun Lal K M 781e7725610SArun Lal K M if (!pKnob->Attribute("name") || !pKnob->Attribute("CurrentVal")) 782e7725610SArun Lal K M { 783e7725610SArun Lal K M return; 784e7725610SArun Lal K M } 785e7725610SArun Lal K M 786e7725610SArun Lal K M nameStr = pKnob->Attribute("name"); 787e7725610SArun Lal K M currentValStr = pKnob->Attribute("CurrentVal"); 788e7725610SArun Lal K M 789e7725610SArun Lal K M try 790e7725610SArun Lal K M { 791e7725610SArun Lal K M currentVal = std::stoi(currentValStr); 792e7725610SArun Lal K M } 793e7725610SArun Lal K M catch (std::exception& ex) 794e7725610SArun Lal K M { 795e7725610SArun Lal K M phosphor::logging::log<phosphor::logging::level::ERR>( 796e7725610SArun Lal K M ex.what()); 797e7725610SArun Lal K M return; 798e7725610SArun Lal K M } 799e7725610SArun Lal K M 800e7725610SArun Lal K M if (pKnob->Attribute("description")) 801e7725610SArun Lal K M descriptionStr = pKnob->Attribute("description"); 802e7725610SArun Lal K M 803e7725610SArun Lal K M if (pKnob->Attribute("default")) 804e7725610SArun Lal K M defaultStr = pKnob->Attribute("default"); 805e7725610SArun Lal K M 806e7725610SArun Lal K M if (pKnob->Attribute("depex")) 807e7725610SArun Lal K M depexStr = pKnob->Attribute("depex"); 808e7725610SArun Lal K M 809e7725610SArun Lal K M if (pKnob->Attribute("prompt")) 810e7725610SArun Lal K M promptStr = pKnob->Attribute("prompt"); 811e7725610SArun Lal K M 812e7725610SArun Lal K M if (pKnob->Attribute("setupType")) 813e7725610SArun Lal K M setupTypeStr = pKnob->Attribute("setupType"); 814e7725610SArun Lal K M 815e7725610SArun Lal K M mKnobs.emplace_back(nameStr, currentValStr, currentVal, 816e7725610SArun Lal K M descriptionStr, defaultStr, promptStr, depexStr, 817e7725610SArun Lal K M setupTypeStr); 818e7725610SArun Lal K M 819e7725610SArun Lal K M getOptions(pKnob); 820e7725610SArun Lal K M } 821e7725610SArun Lal K M } 822e7725610SArun Lal K M 823e7725610SArun Lal K M /* Get 'biosknobs' */ 824e7725610SArun Lal K M bool getKnobs(const char* biosXmlFilePath) 825e7725610SArun Lal K M { 826e7725610SArun Lal K M uint16_t reserveCnt = 0; 827e7725610SArun Lal K M 828e7725610SArun Lal K M mKnobs.clear(); 829e7725610SArun Lal K M 830e7725610SArun Lal K M tinyxml2::XMLDocument biosXml; 831e7725610SArun Lal K M 832e7725610SArun Lal K M /* Load the XML file into the Doc instance */ 833e7725610SArun Lal K M biosXml.LoadFile(biosXmlFilePath); 834e7725610SArun Lal K M 835e7725610SArun Lal K M /* Get 'SYSTEM' */ 836e7725610SArun Lal K M tinyxml2::XMLElement* pRootElement = biosXml.RootElement(); 837e7725610SArun Lal K M if (pRootElement) 838e7725610SArun Lal K M { 839e7725610SArun Lal K M /* Get 'biosknobs' inside 'SYSTEM' */ 840e7725610SArun Lal K M tinyxml2::XMLElement* pBiosknobs = 841e7725610SArun Lal K M pRootElement->FirstChildElement("biosknobs"); 842e7725610SArun Lal K M if (pBiosknobs) 843e7725610SArun Lal K M { 844e7725610SArun Lal K M for (tinyxml2::XMLElement* pKnob = 845e7725610SArun Lal K M pBiosknobs->FirstChildElement("knob"); 846e7725610SArun Lal K M pKnob; pKnob = pKnob->NextSiblingElement("knob")) 847e7725610SArun Lal K M { 848e7725610SArun Lal K M ++reserveCnt; 849e7725610SArun Lal K M } 850e7725610SArun Lal K M 851e7725610SArun Lal K M /* reserve before emplace_back will avoids realloc(s) */ 852e7725610SArun Lal K M mKnobs.reserve(reserveCnt); 853e7725610SArun Lal K M 854e7725610SArun Lal K M for (tinyxml2::XMLElement* pKnob = 855e7725610SArun Lal K M pBiosknobs->FirstChildElement("knob"); 856e7725610SArun Lal K M pKnob; pKnob = pKnob->NextSiblingElement("knob")) 857e7725610SArun Lal K M { 858e7725610SArun Lal K M getKnob(pKnob); 859e7725610SArun Lal K M } 860e7725610SArun Lal K M } 861e7725610SArun Lal K M } 862e7725610SArun Lal K M 863e7725610SArun Lal K M if (!mKnobs.empty()) 864e7725610SArun Lal K M { 865e7725610SArun Lal K M return true; 866e7725610SArun Lal K M } 867e7725610SArun Lal K M 868e7725610SArun Lal K M return false; 869e7725610SArun Lal K M } 870e7725610SArun Lal K M 871e7725610SArun Lal K M private: 872e7725610SArun Lal K M /* To store all 'knob's in 'biosknobs' */ 873e7725610SArun Lal K M std::vector<knob::knob> mKnobs; 874e7725610SArun Lal K M 875e7725610SArun Lal K M /* Object of Depex class to compute 'depex' expression */ 876e7725610SArun Lal K M std::unique_ptr<Depex> mDepex; 877e7725610SArun Lal K M }; 878e7725610SArun Lal K M } // namespace bios 879